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(const char *name)
537 UI_METHOD *ui_method = OPENSSL_zalloc(sizeof(*ui_method));
539 if (ui_method != NULL) {
540 ui_method->name = OPENSSL_strdup(name);
541 if (ui_method->name == NULL) {
542 OPENSSL_free(ui_method);
543 UIerr(UI_F_UI_CREATE_METHOD, ERR_R_MALLOC_FAILURE);
551 * BIG FSCKING WARNING!!!! If you use this on a statically allocated method
552 * (that is, it hasn't been allocated using UI_create_method(), you deserve
553 * anything Murphy can throw at you and more! You have been warned.
555 void UI_destroy_method(UI_METHOD *ui_method)
557 OPENSSL_free(ui_method->name);
558 ui_method->name = NULL;
559 OPENSSL_free(ui_method);
562 int UI_method_set_opener(UI_METHOD *method, int (*opener) (UI *ui))
565 method->ui_open_session = opener;
571 int UI_method_set_writer(UI_METHOD *method,
572 int (*writer) (UI *ui, UI_STRING *uis))
575 method->ui_write_string = writer;
581 int UI_method_set_flusher(UI_METHOD *method, int (*flusher) (UI *ui))
584 method->ui_flush = flusher;
590 int UI_method_set_reader(UI_METHOD *method,
591 int (*reader) (UI *ui, UI_STRING *uis))
594 method->ui_read_string = reader;
600 int UI_method_set_closer(UI_METHOD *method, int (*closer) (UI *ui))
603 method->ui_close_session = closer;
609 int UI_method_set_prompt_constructor(UI_METHOD *method,
610 char *(*prompt_constructor) (UI *ui,
617 method->ui_construct_prompt = prompt_constructor;
623 int (*UI_method_get_opener(UI_METHOD *method)) (UI *) {
625 return method->ui_open_session;
630 int (*UI_method_get_writer(UI_METHOD *method)) (UI *, UI_STRING *) {
632 return method->ui_write_string;
637 int (*UI_method_get_flusher(UI_METHOD *method)) (UI *) {
639 return method->ui_flush;
644 int (*UI_method_get_reader(UI_METHOD *method)) (UI *, UI_STRING *) {
646 return method->ui_read_string;
651 int (*UI_method_get_closer(UI_METHOD *method)) (UI *) {
653 return method->ui_close_session;
658 char *(*UI_method_get_prompt_constructor(UI_METHOD *method)) (UI *,
662 return method->ui_construct_prompt;
667 enum UI_string_types UI_get_string_type(UI_STRING *uis)
674 int UI_get_input_flags(UI_STRING *uis)
678 return uis->input_flags;
681 const char *UI_get0_output_string(UI_STRING *uis)
685 return uis->out_string;
688 const char *UI_get0_action_string(UI_STRING *uis)
695 return uis->_.boolean_data.action_desc;
701 const char *UI_get0_result_string(UI_STRING *uis)
708 return uis->result_buf;
714 const char *UI_get0_test_string(UI_STRING *uis)
720 return uis->_.string_data.test_buf;
726 int UI_get_result_minsize(UI_STRING *uis)
733 return uis->_.string_data.result_minsize;
739 int UI_get_result_maxsize(UI_STRING *uis)
746 return uis->_.string_data.result_maxsize;
752 int UI_set_result(UI *ui, UI_STRING *uis, const char *result)
754 int l = strlen(result);
756 ui->flags &= ~UI_FLAG_REDOABLE;
764 char number1[DECIMAL_SIZE(uis->_.string_data.result_minsize) + 1];
765 char number2[DECIMAL_SIZE(uis->_.string_data.result_maxsize) + 1];
767 BIO_snprintf(number1, sizeof(number1), "%d",
768 uis->_.string_data.result_minsize);
769 BIO_snprintf(number2, sizeof(number2), "%d",
770 uis->_.string_data.result_maxsize);
772 if (l < uis->_.string_data.result_minsize) {
773 ui->flags |= UI_FLAG_REDOABLE;
774 UIerr(UI_F_UI_SET_RESULT, UI_R_RESULT_TOO_SMALL);
775 ERR_add_error_data(5, "You must type in ",
776 number1, " to ", number2, " characters");
779 if (l > uis->_.string_data.result_maxsize) {
780 ui->flags |= UI_FLAG_REDOABLE;
781 UIerr(UI_F_UI_SET_RESULT, UI_R_RESULT_TOO_LARGE);
782 ERR_add_error_data(5, "You must type in ",
783 number1, " to ", number2, " characters");
788 if (!uis->result_buf) {
789 UIerr(UI_F_UI_SET_RESULT, UI_R_NO_RESULT_BUFFER);
793 OPENSSL_strlcpy(uis->result_buf, result,
794 uis->_.string_data.result_maxsize + 1);
800 if (!uis->result_buf) {
801 UIerr(UI_F_UI_SET_RESULT, UI_R_NO_RESULT_BUFFER);
805 uis->result_buf[0] = '\0';
806 for (p = result; *p; p++) {
807 if (strchr(uis->_.boolean_data.ok_chars, *p)) {
808 uis->result_buf[0] = uis->_.boolean_data.ok_chars[0];
811 if (strchr(uis->_.boolean_data.cancel_chars, *p)) {
812 uis->result_buf[0] = uis->_.boolean_data.cancel_chars[0];