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>
20 return (UI_new_method(NULL));
23 UI *UI_new_method(const UI_METHOD *method)
25 UI *ret = OPENSSL_zalloc(sizeof(*ret));
28 UIerr(UI_F_UI_NEW_METHOD, ERR_R_MALLOC_FAILURE);
32 ret->lock = CRYPTO_THREAD_lock_new();
33 if (ret->lock == NULL) {
34 UIerr(UI_F_UI_NEW_METHOD, ERR_R_MALLOC_FAILURE);
40 ret->meth = UI_get_default_method();
44 if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_UI, ret, &ret->ex_data)) {
51 static void free_string(UI_STRING *uis)
53 if (uis->flags & OUT_STRING_FREEABLE) {
54 OPENSSL_free((char *)uis->out_string);
57 OPENSSL_free((char *)uis->_.boolean_data.action_desc);
58 OPENSSL_free((char *)uis->_.boolean_data.ok_chars);
59 OPENSSL_free((char *)uis->_.boolean_data.cancel_chars);
76 sk_UI_STRING_pop_free(ui->strings, free_string);
77 CRYPTO_free_ex_data(CRYPTO_EX_INDEX_UI, ui, &ui->ex_data);
78 CRYPTO_THREAD_lock_free(ui->lock);
82 static int allocate_string_stack(UI *ui)
84 if (ui->strings == NULL) {
85 ui->strings = sk_UI_STRING_new_null();
86 if (ui->strings == NULL) {
93 static UI_STRING *general_allocate_prompt(UI *ui, const char *prompt,
95 enum UI_string_types type,
96 int input_flags, char *result_buf)
98 UI_STRING *ret = NULL;
100 if (prompt == NULL) {
101 UIerr(UI_F_GENERAL_ALLOCATE_PROMPT, ERR_R_PASSED_NULL_PARAMETER);
102 } else if ((type == UIT_PROMPT || type == UIT_VERIFY
103 || type == UIT_BOOLEAN) && result_buf == NULL) {
104 UIerr(UI_F_GENERAL_ALLOCATE_PROMPT, UI_R_NO_RESULT_BUFFER);
105 } else if ((ret = OPENSSL_malloc(sizeof(*ret))) != NULL) {
106 ret->out_string = prompt;
107 ret->flags = prompt_freeable ? OUT_STRING_FREEABLE : 0;
108 ret->input_flags = input_flags;
110 ret->result_buf = result_buf;
115 static int general_allocate_string(UI *ui, const char *prompt,
117 enum UI_string_types type, int input_flags,
118 char *result_buf, int minsize, int maxsize,
119 const char *test_buf)
122 UI_STRING *s = general_allocate_prompt(ui, prompt, prompt_freeable,
123 type, input_flags, result_buf);
126 if (allocate_string_stack(ui) >= 0) {
127 s->_.string_data.result_minsize = minsize;
128 s->_.string_data.result_maxsize = maxsize;
129 s->_.string_data.test_buf = test_buf;
130 ret = sk_UI_STRING_push(ui->strings, s);
131 /* sk_push() returns 0 on error. Let's adapt that */
142 static int general_allocate_boolean(UI *ui,
144 const char *action_desc,
145 const char *ok_chars,
146 const char *cancel_chars,
148 enum UI_string_types type,
149 int input_flags, char *result_buf)
155 if (ok_chars == NULL) {
156 UIerr(UI_F_GENERAL_ALLOCATE_BOOLEAN, ERR_R_PASSED_NULL_PARAMETER);
157 } else if (cancel_chars == NULL) {
158 UIerr(UI_F_GENERAL_ALLOCATE_BOOLEAN, ERR_R_PASSED_NULL_PARAMETER);
160 for (p = ok_chars; *p != '\0'; p++) {
161 if (strchr(cancel_chars, *p) != NULL) {
162 UIerr(UI_F_GENERAL_ALLOCATE_BOOLEAN,
163 UI_R_COMMON_OK_AND_CANCEL_CHARACTERS);
167 s = general_allocate_prompt(ui, prompt, prompt_freeable,
168 type, input_flags, result_buf);
171 if (allocate_string_stack(ui) >= 0) {
172 s->_.boolean_data.action_desc = action_desc;
173 s->_.boolean_data.ok_chars = ok_chars;
174 s->_.boolean_data.cancel_chars = cancel_chars;
175 ret = sk_UI_STRING_push(ui->strings, s);
177 * sk_push() returns 0 on error. Let's adapt that
191 * Returns the index to the place in the stack or -1 for error. Uses a
192 * direct reference to the prompt.
194 int UI_add_input_string(UI *ui, const char *prompt, int flags,
195 char *result_buf, int minsize, int maxsize)
197 return general_allocate_string(ui, prompt, 0,
198 UIT_PROMPT, flags, result_buf, minsize,
202 /* Same as UI_add_input_string(), excepts it takes a copy of the prompt */
203 int UI_dup_input_string(UI *ui, const char *prompt, int flags,
204 char *result_buf, int minsize, int maxsize)
206 char *prompt_copy = NULL;
208 if (prompt != NULL) {
209 prompt_copy = OPENSSL_strdup(prompt);
210 if (prompt_copy == NULL) {
211 UIerr(UI_F_UI_DUP_INPUT_STRING, ERR_R_MALLOC_FAILURE);
216 return general_allocate_string(ui, prompt_copy, 1,
217 UIT_PROMPT, flags, result_buf, minsize,
221 int UI_add_verify_string(UI *ui, const char *prompt, int flags,
222 char *result_buf, int minsize, int maxsize,
223 const char *test_buf)
225 return general_allocate_string(ui, prompt, 0,
226 UIT_VERIFY, flags, result_buf, minsize,
230 int UI_dup_verify_string(UI *ui, const char *prompt, int flags,
231 char *result_buf, int minsize, int maxsize,
232 const char *test_buf)
234 char *prompt_copy = NULL;
236 if (prompt != NULL) {
237 prompt_copy = OPENSSL_strdup(prompt);
238 if (prompt_copy == NULL) {
239 UIerr(UI_F_UI_DUP_VERIFY_STRING, ERR_R_MALLOC_FAILURE);
244 return general_allocate_string(ui, prompt_copy, 1,
245 UIT_VERIFY, flags, result_buf, minsize,
249 int UI_add_input_boolean(UI *ui, const char *prompt, const char *action_desc,
250 const char *ok_chars, const char *cancel_chars,
251 int flags, char *result_buf)
253 return general_allocate_boolean(ui, prompt, action_desc,
254 ok_chars, cancel_chars, 0, UIT_BOOLEAN,
258 int UI_dup_input_boolean(UI *ui, const char *prompt, const char *action_desc,
259 const char *ok_chars, const char *cancel_chars,
260 int flags, char *result_buf)
262 char *prompt_copy = NULL;
263 char *action_desc_copy = NULL;
264 char *ok_chars_copy = NULL;
265 char *cancel_chars_copy = NULL;
267 if (prompt != NULL) {
268 prompt_copy = OPENSSL_strdup(prompt);
269 if (prompt_copy == NULL) {
270 UIerr(UI_F_UI_DUP_INPUT_BOOLEAN, ERR_R_MALLOC_FAILURE);
275 if (action_desc != NULL) {
276 action_desc_copy = OPENSSL_strdup(action_desc);
277 if (action_desc_copy == NULL) {
278 UIerr(UI_F_UI_DUP_INPUT_BOOLEAN, ERR_R_MALLOC_FAILURE);
283 if (ok_chars != NULL) {
284 ok_chars_copy = OPENSSL_strdup(ok_chars);
285 if (ok_chars_copy == NULL) {
286 UIerr(UI_F_UI_DUP_INPUT_BOOLEAN, ERR_R_MALLOC_FAILURE);
291 if (cancel_chars != NULL) {
292 cancel_chars_copy = OPENSSL_strdup(cancel_chars);
293 if (cancel_chars_copy == NULL) {
294 UIerr(UI_F_UI_DUP_INPUT_BOOLEAN, ERR_R_MALLOC_FAILURE);
299 return general_allocate_boolean(ui, prompt_copy, action_desc_copy,
300 ok_chars_copy, cancel_chars_copy, 1,
301 UIT_BOOLEAN, flags, result_buf);
303 OPENSSL_free(prompt_copy);
304 OPENSSL_free(action_desc_copy);
305 OPENSSL_free(ok_chars_copy);
306 OPENSSL_free(cancel_chars_copy);
310 int UI_add_info_string(UI *ui, const char *text)
312 return general_allocate_string(ui, text, 0, UIT_INFO, 0, NULL, 0, 0,
316 int UI_dup_info_string(UI *ui, const char *text)
318 char *text_copy = NULL;
321 text_copy = OPENSSL_strdup(text);
322 if (text_copy == NULL) {
323 UIerr(UI_F_UI_DUP_INFO_STRING, ERR_R_MALLOC_FAILURE);
328 return general_allocate_string(ui, text_copy, 1, UIT_INFO, 0, NULL,
332 int UI_add_error_string(UI *ui, const char *text)
334 return general_allocate_string(ui, text, 0, UIT_ERROR, 0, NULL, 0, 0,
338 int UI_dup_error_string(UI *ui, const char *text)
340 char *text_copy = NULL;
343 text_copy = OPENSSL_strdup(text);
344 if (text_copy == NULL) {
345 UIerr(UI_F_UI_DUP_ERROR_STRING, ERR_R_MALLOC_FAILURE);
349 return general_allocate_string(ui, text_copy, 1, UIT_ERROR, 0, NULL,
353 char *UI_construct_prompt(UI *ui, const char *object_desc,
354 const char *object_name)
358 if (ui->meth->ui_construct_prompt != NULL)
359 prompt = ui->meth->ui_construct_prompt(ui, object_desc, object_name);
361 char prompt1[] = "Enter ";
362 char prompt2[] = " for ";
363 char prompt3[] = ":";
366 if (object_desc == NULL)
368 len = sizeof(prompt1) - 1 + strlen(object_desc);
369 if (object_name != NULL)
370 len += sizeof(prompt2) - 1 + strlen(object_name);
371 len += sizeof(prompt3) - 1;
373 prompt = OPENSSL_malloc(len + 1);
376 OPENSSL_strlcpy(prompt, prompt1, len + 1);
377 OPENSSL_strlcat(prompt, object_desc, len + 1);
378 if (object_name != NULL) {
379 OPENSSL_strlcat(prompt, prompt2, len + 1);
380 OPENSSL_strlcat(prompt, object_name, len + 1);
382 OPENSSL_strlcat(prompt, prompt3, len + 1);
387 void *UI_add_user_data(UI *ui, void *user_data)
389 void *old_data = ui->user_data;
390 ui->user_data = user_data;
394 void *UI_get0_user_data(UI *ui)
396 return ui->user_data;
399 const char *UI_get0_result(UI *ui, int i)
402 UIerr(UI_F_UI_GET0_RESULT, UI_R_INDEX_TOO_SMALL);
405 if (i >= sk_UI_STRING_num(ui->strings)) {
406 UIerr(UI_F_UI_GET0_RESULT, UI_R_INDEX_TOO_LARGE);
409 return UI_get0_result_string(sk_UI_STRING_value(ui->strings, i));
412 static int print_error(const char *str, size_t len, UI *ui)
416 memset(&uis, 0, sizeof(uis));
417 uis.type = UIT_ERROR;
418 uis.out_string = str;
420 if (ui->meth->ui_write_string != NULL
421 && ui->meth->ui_write_string(ui, &uis) <= 0)
426 int UI_process(UI *ui)
429 const char *state = "processing";
431 if (ui->meth->ui_open_session != NULL
432 && ui->meth->ui_open_session(ui) <= 0) {
433 state = "opening session";
438 if (ui->flags & UI_FLAG_PRINT_ERRORS)
439 ERR_print_errors_cb((int (*)(const char *, size_t, void *))
440 print_error, (void *)ui);
442 for (i = 0; i < sk_UI_STRING_num(ui->strings); i++) {
443 if (ui->meth->ui_write_string != NULL
444 && (ui->meth->ui_write_string(ui,
445 sk_UI_STRING_value(ui->strings, i))
448 state = "writing strings";
454 if (ui->meth->ui_flush != NULL)
455 switch (ui->meth->ui_flush(ui)) {
456 case -1: /* Interrupt/Cancel/something... */
463 default: /* Success */
468 for (i = 0; i < sk_UI_STRING_num(ui->strings); i++) {
469 if (ui->meth->ui_read_string != NULL) {
470 switch (ui->meth->ui_read_string(ui,
471 sk_UI_STRING_value(ui->strings,
473 case -1: /* Interrupt/Cancel/something... */
477 state = "reading strings";
480 default: /* Success */
487 if (ui->meth->ui_close_session != NULL
488 && ui->meth->ui_close_session(ui) <= 0) {
490 state = "closing session";
495 UIerr(UI_F_UI_PROCESS, UI_R_PROCESSING_ERROR);
496 ERR_add_error_data(2, "while ", state);
501 int UI_ctrl(UI *ui, int cmd, long i, void *p, void (*f) (void))
504 UIerr(UI_F_UI_CTRL, ERR_R_PASSED_NULL_PARAMETER);
508 case UI_CTRL_PRINT_ERRORS:
510 int save_flag = ! !(ui->flags & UI_FLAG_PRINT_ERRORS);
512 ui->flags |= UI_FLAG_PRINT_ERRORS;
514 ui->flags &= ~UI_FLAG_PRINT_ERRORS;
517 case UI_CTRL_IS_REDOABLE:
518 return ! !(ui->flags & UI_FLAG_REDOABLE);
522 UIerr(UI_F_UI_CTRL, UI_R_UNKNOWN_CONTROL_COMMAND);
526 int UI_set_ex_data(UI *r, int idx, void *arg)
528 return (CRYPTO_set_ex_data(&r->ex_data, idx, arg));
531 void *UI_get_ex_data(UI *r, int idx)
533 return (CRYPTO_get_ex_data(&r->ex_data, idx));
536 const UI_METHOD *UI_get_method(UI *ui)
541 const UI_METHOD *UI_set_method(UI *ui, const UI_METHOD *meth)
547 UI_METHOD *UI_create_method(const char *name)
549 UI_METHOD *ui_method = NULL;
551 if ((ui_method = OPENSSL_zalloc(sizeof(*ui_method))) == NULL
552 || (ui_method->name = OPENSSL_strdup(name)) == NULL
553 || !CRYPTO_new_ex_data(CRYPTO_EX_INDEX_UI_METHOD, ui_method,
554 &ui_method->ex_data)) {
556 OPENSSL_free(ui_method->name);
557 OPENSSL_free(ui_method);
558 UIerr(UI_F_UI_CREATE_METHOD, ERR_R_MALLOC_FAILURE);
565 * BIG FSCKING WARNING!!!! If you use this on a statically allocated method
566 * (that is, it hasn't been allocated using UI_create_method(), you deserve
567 * anything Murphy can throw at you and more! You have been warned.
569 void UI_destroy_method(UI_METHOD *ui_method)
571 if (ui_method == NULL)
573 CRYPTO_free_ex_data(CRYPTO_EX_INDEX_UI_METHOD, ui_method,
574 &ui_method->ex_data);
575 OPENSSL_free(ui_method->name);
576 ui_method->name = NULL;
577 OPENSSL_free(ui_method);
580 int UI_method_set_opener(UI_METHOD *method, int (*opener) (UI *ui))
582 if (method != NULL) {
583 method->ui_open_session = opener;
589 int UI_method_set_writer(UI_METHOD *method,
590 int (*writer) (UI *ui, UI_STRING *uis))
592 if (method != NULL) {
593 method->ui_write_string = writer;
599 int UI_method_set_flusher(UI_METHOD *method, int (*flusher) (UI *ui))
601 if (method != NULL) {
602 method->ui_flush = flusher;
608 int UI_method_set_reader(UI_METHOD *method,
609 int (*reader) (UI *ui, UI_STRING *uis))
611 if (method != NULL) {
612 method->ui_read_string = reader;
618 int UI_method_set_closer(UI_METHOD *method, int (*closer) (UI *ui))
620 if (method != NULL) {
621 method->ui_close_session = closer;
627 int UI_method_set_prompt_constructor(UI_METHOD *method,
628 char *(*prompt_constructor) (UI *ui,
634 if (method != NULL) {
635 method->ui_construct_prompt = prompt_constructor;
641 int UI_method_set_ex_data(UI_METHOD *method, int idx, void *data)
643 return CRYPTO_set_ex_data(&method->ex_data, idx, data);
646 int (*UI_method_get_opener(const UI_METHOD *method)) (UI *)
649 return method->ui_open_session;
653 int (*UI_method_get_writer(const UI_METHOD *method)) (UI *, UI_STRING *)
656 return method->ui_write_string;
660 int (*UI_method_get_flusher(const UI_METHOD *method)) (UI *)
663 return method->ui_flush;
667 int (*UI_method_get_reader(const UI_METHOD *method)) (UI *, UI_STRING *)
670 return method->ui_read_string;
674 int (*UI_method_get_closer(const UI_METHOD *method)) (UI *)
677 return method->ui_close_session;
681 char *(*UI_method_get_prompt_constructor(const UI_METHOD *method))
682 (UI *, const char *, const char *)
685 return method->ui_construct_prompt;
689 const void *UI_method_get_ex_data(const UI_METHOD *method, int idx)
691 return CRYPTO_get_ex_data(&method->ex_data, idx);
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)
713 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];