2 * Copyright 2001-2023 The OpenSSL Project Authors. All Rights Reserved.
4 * Licensed under the Apache License 2.0 (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));
30 ret->lock = CRYPTO_THREAD_lock_new();
31 if (ret->lock == NULL) {
32 ERR_raise(ERR_LIB_UI, ERR_R_CRYPTO_LIB);
38 method = UI_get_default_method();
43 if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_UI, ret, &ret->ex_data)) {
50 static void free_string(UI_STRING *uis)
52 if (uis->flags & OUT_STRING_FREEABLE) {
53 OPENSSL_free((char *)uis->out_string);
56 OPENSSL_free((char *)uis->_.boolean_data.action_desc);
57 OPENSSL_free((char *)uis->_.boolean_data.ok_chars);
58 OPENSSL_free((char *)uis->_.boolean_data.cancel_chars);
75 if ((ui->flags & UI_FLAG_DUPL_DATA) != 0) {
76 ui->meth->ui_destroy_data(ui, ui->user_data);
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 ERR_raise(ERR_LIB_UI, ERR_R_PASSED_NULL_PARAMETER);
104 } else if ((type == UIT_PROMPT || type == UIT_VERIFY
105 || type == UIT_BOOLEAN) && result_buf == NULL) {
106 ERR_raise(ERR_LIB_UI, UI_R_NO_RESULT_BUFFER);
107 } else if ((ret = OPENSSL_zalloc(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 ERR_raise(ERR_LIB_UI, ERR_R_PASSED_NULL_PARAMETER);
159 } else if (cancel_chars == NULL) {
160 ERR_raise(ERR_LIB_UI, ERR_R_PASSED_NULL_PARAMETER);
162 for (p = ok_chars; *p != '\0'; p++) {
163 if (strchr(cancel_chars, *p) != NULL) {
164 ERR_raise(ERR_LIB_UI, UI_R_COMMON_OK_AND_CANCEL_CHARACTERS);
168 s = general_allocate_prompt(ui, prompt, prompt_freeable,
169 type, input_flags, result_buf);
172 if (allocate_string_stack(ui) >= 0) {
173 s->_.boolean_data.action_desc = action_desc;
174 s->_.boolean_data.ok_chars = ok_chars;
175 s->_.boolean_data.cancel_chars = cancel_chars;
176 ret = sk_UI_STRING_push(ui->strings, s);
178 * sk_push() returns 0 on error. Let's adapt that
192 * Returns the index to the place in the stack or -1 for error. Uses a
193 * direct reference to the prompt.
195 int UI_add_input_string(UI *ui, const char *prompt, int flags,
196 char *result_buf, int minsize, int maxsize)
198 return general_allocate_string(ui, prompt, 0,
199 UIT_PROMPT, flags, result_buf, minsize,
203 /* Same as UI_add_input_string(), excepts it takes a copy of the prompt */
204 int UI_dup_input_string(UI *ui, const char *prompt, int flags,
205 char *result_buf, int minsize, int maxsize)
207 char *prompt_copy = NULL;
209 if (prompt != NULL) {
210 prompt_copy = OPENSSL_strdup(prompt);
211 if (prompt_copy == NULL)
215 return general_allocate_string(ui, prompt_copy, 1,
216 UIT_PROMPT, flags, result_buf, minsize,
220 int UI_add_verify_string(UI *ui, const char *prompt, int flags,
221 char *result_buf, int minsize, int maxsize,
222 const char *test_buf)
224 return general_allocate_string(ui, prompt, 0,
225 UIT_VERIFY, flags, result_buf, minsize,
229 int UI_dup_verify_string(UI *ui, const char *prompt, int flags,
230 char *result_buf, int minsize, int maxsize,
231 const char *test_buf)
233 char *prompt_copy = NULL;
235 if (prompt != NULL) {
236 prompt_copy = OPENSSL_strdup(prompt);
237 if (prompt_copy == NULL)
241 return general_allocate_string(ui, prompt_copy, 1,
242 UIT_VERIFY, flags, result_buf, minsize,
246 int UI_add_input_boolean(UI *ui, const char *prompt, const char *action_desc,
247 const char *ok_chars, const char *cancel_chars,
248 int flags, char *result_buf)
250 return general_allocate_boolean(ui, prompt, action_desc,
251 ok_chars, cancel_chars, 0, UIT_BOOLEAN,
255 int UI_dup_input_boolean(UI *ui, const char *prompt, const char *action_desc,
256 const char *ok_chars, const char *cancel_chars,
257 int flags, char *result_buf)
259 char *prompt_copy = NULL;
260 char *action_desc_copy = NULL;
261 char *ok_chars_copy = NULL;
262 char *cancel_chars_copy = NULL;
264 if (prompt != NULL) {
265 prompt_copy = OPENSSL_strdup(prompt);
266 if (prompt_copy == NULL)
270 if (action_desc != NULL) {
271 action_desc_copy = OPENSSL_strdup(action_desc);
272 if (action_desc_copy == NULL)
276 if (ok_chars != NULL) {
277 ok_chars_copy = OPENSSL_strdup(ok_chars);
278 if (ok_chars_copy == NULL)
282 if (cancel_chars != NULL) {
283 cancel_chars_copy = OPENSSL_strdup(cancel_chars);
284 if (cancel_chars_copy == NULL)
288 return general_allocate_boolean(ui, prompt_copy, action_desc_copy,
289 ok_chars_copy, cancel_chars_copy, 1,
290 UIT_BOOLEAN, flags, result_buf);
292 OPENSSL_free(prompt_copy);
293 OPENSSL_free(action_desc_copy);
294 OPENSSL_free(ok_chars_copy);
295 OPENSSL_free(cancel_chars_copy);
299 int UI_add_info_string(UI *ui, const char *text)
301 return general_allocate_string(ui, text, 0, UIT_INFO, 0, NULL, 0, 0,
305 int UI_dup_info_string(UI *ui, const char *text)
307 char *text_copy = NULL;
310 text_copy = OPENSSL_strdup(text);
311 if (text_copy == NULL)
315 return general_allocate_string(ui, text_copy, 1, UIT_INFO, 0, NULL,
319 int UI_add_error_string(UI *ui, const char *text)
321 return general_allocate_string(ui, text, 0, UIT_ERROR, 0, NULL, 0, 0,
325 int UI_dup_error_string(UI *ui, const char *text)
327 char *text_copy = NULL;
330 text_copy = OPENSSL_strdup(text);
331 if (text_copy == NULL)
334 return general_allocate_string(ui, text_copy, 1, UIT_ERROR, 0, NULL,
338 char *UI_construct_prompt(UI *ui, const char *phrase_desc,
339 const char *object_name)
343 if (ui != NULL && ui->meth != NULL && ui->meth->ui_construct_prompt != NULL)
344 prompt = ui->meth->ui_construct_prompt(ui, phrase_desc, object_name);
346 char prompt1[] = "Enter ";
347 char prompt2[] = " for ";
348 char prompt3[] = ":";
351 if (phrase_desc == NULL)
353 len = sizeof(prompt1) - 1 + strlen(phrase_desc);
354 if (object_name != NULL)
355 len += sizeof(prompt2) - 1 + strlen(object_name);
356 len += sizeof(prompt3) - 1;
358 if ((prompt = OPENSSL_malloc(len + 1)) == NULL)
360 OPENSSL_strlcpy(prompt, prompt1, len + 1);
361 OPENSSL_strlcat(prompt, phrase_desc, len + 1);
362 if (object_name != NULL) {
363 OPENSSL_strlcat(prompt, prompt2, len + 1);
364 OPENSSL_strlcat(prompt, object_name, len + 1);
366 OPENSSL_strlcat(prompt, prompt3, len + 1);
371 void *UI_add_user_data(UI *ui, void *user_data)
373 void *old_data = ui->user_data;
375 if ((ui->flags & UI_FLAG_DUPL_DATA) != 0) {
376 ui->meth->ui_destroy_data(ui, old_data);
379 ui->user_data = user_data;
380 ui->flags &= ~UI_FLAG_DUPL_DATA;
384 int UI_dup_user_data(UI *ui, void *user_data)
386 void *duplicate = NULL;
388 if (ui->meth->ui_duplicate_data == NULL
389 || ui->meth->ui_destroy_data == NULL) {
390 ERR_raise(ERR_LIB_UI, UI_R_USER_DATA_DUPLICATION_UNSUPPORTED);
394 duplicate = ui->meth->ui_duplicate_data(ui, user_data);
395 if (duplicate == NULL) {
396 ERR_raise(ERR_LIB_UI, ERR_R_UI_LIB);
400 (void)UI_add_user_data(ui, duplicate);
401 ui->flags |= UI_FLAG_DUPL_DATA;
406 void *UI_get0_user_data(UI *ui)
408 return ui->user_data;
411 const char *UI_get0_result(UI *ui, int i)
414 ERR_raise(ERR_LIB_UI, UI_R_INDEX_TOO_SMALL);
417 if (i >= sk_UI_STRING_num(ui->strings)) {
418 ERR_raise(ERR_LIB_UI, UI_R_INDEX_TOO_LARGE);
421 return UI_get0_result_string(sk_UI_STRING_value(ui->strings, i));
424 int UI_get_result_length(UI *ui, int i)
427 ERR_raise(ERR_LIB_UI, UI_R_INDEX_TOO_SMALL);
430 if (i >= sk_UI_STRING_num(ui->strings)) {
431 ERR_raise(ERR_LIB_UI, UI_R_INDEX_TOO_LARGE);
434 return UI_get_result_string_length(sk_UI_STRING_value(ui->strings, i));
437 static int print_error(const char *str, size_t len, UI *ui)
441 memset(&uis, 0, sizeof(uis));
442 uis.type = UIT_ERROR;
443 uis.out_string = str;
445 if (ui->meth->ui_write_string != NULL
446 && ui->meth->ui_write_string(ui, &uis) <= 0)
451 int UI_process(UI *ui)
454 const char *state = "processing";
456 if (ui->meth->ui_open_session != NULL
457 && ui->meth->ui_open_session(ui) <= 0) {
458 state = "opening session";
463 if (ui->flags & UI_FLAG_PRINT_ERRORS)
464 ERR_print_errors_cb((int (*)(const char *, size_t, void *))
465 print_error, (void *)ui);
467 for (i = 0; i < sk_UI_STRING_num(ui->strings); i++) {
468 if (ui->meth->ui_write_string != NULL
469 && (ui->meth->ui_write_string(ui,
470 sk_UI_STRING_value(ui->strings, i))
473 state = "writing strings";
479 if (ui->meth->ui_flush != NULL)
480 switch (ui->meth->ui_flush(ui)) {
481 case -1: /* Interrupt/Cancel/something... */
482 ui->flags &= ~UI_FLAG_REDOABLE;
489 default: /* Success */
494 for (i = 0; i < sk_UI_STRING_num(ui->strings); i++) {
495 if (ui->meth->ui_read_string != NULL) {
496 switch (ui->meth->ui_read_string(ui,
497 sk_UI_STRING_value(ui->strings,
499 case -1: /* Interrupt/Cancel/something... */
500 ui->flags &= ~UI_FLAG_REDOABLE;
504 state = "reading strings";
507 default: /* Success */
512 ui->flags &= ~UI_FLAG_REDOABLE;
520 if (ui->meth->ui_close_session != NULL
521 && ui->meth->ui_close_session(ui) <= 0) {
523 state = "closing session";
528 ERR_raise_data(ERR_LIB_UI, UI_R_PROCESSING_ERROR, "while %s", state);
532 int UI_ctrl(UI *ui, int cmd, long i, void *p, void (*f) (void))
535 ERR_raise(ERR_LIB_UI, ERR_R_PASSED_NULL_PARAMETER);
539 case UI_CTRL_PRINT_ERRORS:
541 int save_flag = ! !(ui->flags & UI_FLAG_PRINT_ERRORS);
543 ui->flags |= UI_FLAG_PRINT_ERRORS;
545 ui->flags &= ~UI_FLAG_PRINT_ERRORS;
548 case UI_CTRL_IS_REDOABLE:
549 return ! !(ui->flags & UI_FLAG_REDOABLE);
553 ERR_raise(ERR_LIB_UI, UI_R_UNKNOWN_CONTROL_COMMAND);
557 int UI_set_ex_data(UI *r, int idx, void *arg)
559 return CRYPTO_set_ex_data(&r->ex_data, idx, arg);
562 void *UI_get_ex_data(const UI *r, int idx)
564 return CRYPTO_get_ex_data(&r->ex_data, idx);
567 const UI_METHOD *UI_get_method(UI *ui)
572 const UI_METHOD *UI_set_method(UI *ui, const UI_METHOD *meth)
578 UI_METHOD *UI_create_method(const char *name)
580 UI_METHOD *ui_method = NULL;
582 if ((ui_method = OPENSSL_zalloc(sizeof(*ui_method))) == NULL
583 || (ui_method->name = OPENSSL_strdup(name)) == NULL
584 || !CRYPTO_new_ex_data(CRYPTO_EX_INDEX_UI_METHOD, ui_method,
585 &ui_method->ex_data)) {
587 if (ui_method != NULL) {
588 if (ui_method->name != NULL)
590 * These conditions indicate that the CRYPTO_new_ex_data()
593 ERR_raise(ERR_LIB_UI, ERR_R_CRYPTO_LIB);
594 OPENSSL_free(ui_method->name);
596 OPENSSL_free(ui_method);
603 * BIG FSCKING WARNING!!!! If you use this on a statically allocated method
604 * (that is, it hasn't been allocated using UI_create_method(), you deserve
605 * anything Murphy can throw at you and more! You have been warned.
607 void UI_destroy_method(UI_METHOD *ui_method)
609 if (ui_method == NULL)
611 CRYPTO_free_ex_data(CRYPTO_EX_INDEX_UI_METHOD, ui_method,
612 &ui_method->ex_data);
613 OPENSSL_free(ui_method->name);
614 ui_method->name = NULL;
615 OPENSSL_free(ui_method);
618 int UI_method_set_opener(UI_METHOD *method, int (*opener) (UI *ui))
620 if (method != NULL) {
621 method->ui_open_session = opener;
627 int UI_method_set_writer(UI_METHOD *method,
628 int (*writer) (UI *ui, UI_STRING *uis))
630 if (method != NULL) {
631 method->ui_write_string = writer;
637 int UI_method_set_flusher(UI_METHOD *method, int (*flusher) (UI *ui))
639 if (method != NULL) {
640 method->ui_flush = flusher;
646 int UI_method_set_reader(UI_METHOD *method,
647 int (*reader) (UI *ui, UI_STRING *uis))
649 if (method != NULL) {
650 method->ui_read_string = reader;
656 int UI_method_set_closer(UI_METHOD *method, int (*closer) (UI *ui))
658 if (method != NULL) {
659 method->ui_close_session = closer;
665 int UI_method_set_data_duplicator(UI_METHOD *method,
666 void *(*duplicator) (UI *ui, void *ui_data),
667 void (*destructor)(UI *ui, void *ui_data))
669 if (method != NULL) {
670 method->ui_duplicate_data = duplicator;
671 method->ui_destroy_data = destructor;
677 int UI_method_set_prompt_constructor(UI_METHOD *method,
678 char *(*prompt_constructor) (UI *ui,
682 if (method != NULL) {
683 method->ui_construct_prompt = prompt_constructor;
689 int UI_method_set_ex_data(UI_METHOD *method, int idx, void *data)
691 return CRYPTO_set_ex_data(&method->ex_data, idx, data);
694 int (*UI_method_get_opener(const UI_METHOD *method)) (UI *)
697 return method->ui_open_session;
701 int (*UI_method_get_writer(const UI_METHOD *method)) (UI *, UI_STRING *)
704 return method->ui_write_string;
708 int (*UI_method_get_flusher(const UI_METHOD *method)) (UI *)
711 return method->ui_flush;
715 int (*UI_method_get_reader(const UI_METHOD *method)) (UI *, UI_STRING *)
718 return method->ui_read_string;
722 int (*UI_method_get_closer(const UI_METHOD *method)) (UI *)
725 return method->ui_close_session;
729 char *(*UI_method_get_prompt_constructor(const UI_METHOD *method))
730 (UI *, const char *, const char *)
733 return method->ui_construct_prompt;
737 void *(*UI_method_get_data_duplicator(const UI_METHOD *method)) (UI *, void *)
740 return method->ui_duplicate_data;
744 void (*UI_method_get_data_destructor(const UI_METHOD *method)) (UI *, void *)
747 return method->ui_destroy_data;
751 const void *UI_method_get_ex_data(const UI_METHOD *method, int idx)
753 return CRYPTO_get_ex_data(&method->ex_data, idx);
756 enum UI_string_types UI_get_string_type(UI_STRING *uis)
761 int UI_get_input_flags(UI_STRING *uis)
763 return uis->input_flags;
766 const char *UI_get0_output_string(UI_STRING *uis)
768 return uis->out_string;
771 const char *UI_get0_action_string(UI_STRING *uis)
775 return uis->_.boolean_data.action_desc;
786 const char *UI_get0_result_string(UI_STRING *uis)
791 return uis->result_buf;
801 int UI_get_result_string_length(UI_STRING *uis)
806 return uis->result_len;
816 const char *UI_get0_test_string(UI_STRING *uis)
820 return uis->_.string_data.test_buf;
831 int UI_get_result_minsize(UI_STRING *uis)
836 return uis->_.string_data.result_minsize;
846 int UI_get_result_maxsize(UI_STRING *uis)
851 return uis->_.string_data.result_maxsize;
861 int UI_set_result(UI *ui, UI_STRING *uis, const char *result)
863 return UI_set_result_ex(ui, uis, result, strlen(result));
866 int UI_set_result_ex(UI *ui, UI_STRING *uis, const char *result, int len)
868 ui->flags &= ~UI_FLAG_REDOABLE;
873 if (len < uis->_.string_data.result_minsize) {
874 ui->flags |= UI_FLAG_REDOABLE;
875 ERR_raise_data(ERR_LIB_UI, UI_R_RESULT_TOO_SMALL,
876 "You must type in %d to %d characters",
877 uis->_.string_data.result_minsize,
878 uis->_.string_data.result_maxsize);
881 if (len > uis->_.string_data.result_maxsize) {
882 ui->flags |= UI_FLAG_REDOABLE;
883 ERR_raise_data(ERR_LIB_UI, UI_R_RESULT_TOO_LARGE,
884 "You must type in %d to %d characters",
885 uis->_.string_data.result_minsize,
886 uis->_.string_data.result_maxsize);
890 if (uis->result_buf == NULL) {
891 ERR_raise(ERR_LIB_UI, UI_R_NO_RESULT_BUFFER);
895 memcpy(uis->result_buf, result, len);
896 if (len <= uis->_.string_data.result_maxsize)
897 uis->result_buf[len] = '\0';
898 uis->result_len = len;
904 if (uis->result_buf == NULL) {
905 ERR_raise(ERR_LIB_UI, UI_R_NO_RESULT_BUFFER);
909 uis->result_buf[0] = '\0';
910 for (p = result; *p; p++) {
911 if (strchr(uis->_.boolean_data.ok_chars, *p)) {
912 uis->result_buf[0] = uis->_.boolean_data.ok_chars[0];
915 if (strchr(uis->_.boolean_data.cancel_chars, *p)) {
916 uis->result_buf[0] = uis->_.boolean_data.cancel_chars[0];