xref: /freebsd/crypto/openssl/crypto/ui/ui_lib.c (revision f25b8c9fb4f58cf61adb47d7570abe7caa6d385d)
1 /*
2  * Copyright 2001-2025 The OpenSSL Project Authors. All Rights Reserved.
3  *
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
8  */
9 
10 #include <string.h>
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>
16 #include "ui_local.h"
17 
18 UI *UI_new(void)
19 {
20     return UI_new_method(NULL);
21 }
22 
23 UI *UI_new_method(const UI_METHOD *method)
24 {
25     UI *ret = OPENSSL_zalloc(sizeof(*ret));
26 
27     if (ret == NULL)
28         return NULL;
29 
30     ret->lock = CRYPTO_THREAD_lock_new();
31     if (ret->lock == NULL) {
32         ERR_raise(ERR_LIB_UI, ERR_R_CRYPTO_LIB);
33         OPENSSL_free(ret);
34         return NULL;
35     }
36 
37     if (method == NULL)
38         method = UI_get_default_method();
39     if (method == NULL)
40         method = UI_null();
41     ret->meth = method;
42 
43     if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_UI, ret, &ret->ex_data)) {
44         UI_free(ret);
45         return NULL;
46     }
47     return ret;
48 }
49 
50 static void free_string(UI_STRING *uis)
51 {
52     if (uis->flags & OUT_STRING_FREEABLE) {
53         OPENSSL_free((char *)uis->out_string);
54         switch (uis->type) {
55         case UIT_BOOLEAN:
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);
59             break;
60         case UIT_NONE:
61         case UIT_PROMPT:
62         case UIT_VERIFY:
63         case UIT_ERROR:
64         case UIT_INFO:
65             break;
66         }
67     }
68     OPENSSL_free(uis);
69 }
70 
71 void UI_free(UI *ui)
72 {
73     if (ui == NULL)
74         return;
75     if ((ui->flags & UI_FLAG_DUPL_DATA) != 0) {
76         ui->meth->ui_destroy_data(ui, ui->user_data);
77     }
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);
81     OPENSSL_free(ui);
82 }
83 
84 static int allocate_string_stack(UI *ui)
85 {
86     if (ui->strings == NULL) {
87         ui->strings = sk_UI_STRING_new_null();
88         if (ui->strings == NULL) {
89             return -1;
90         }
91     }
92     return 0;
93 }
94 
95 static UI_STRING *general_allocate_prompt(UI *ui, const char *prompt,
96     int prompt_freeable,
97     enum UI_string_types type,
98     int input_flags, char *result_buf)
99 {
100     UI_STRING *ret = NULL;
101 
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)
106         && result_buf == NULL) {
107         ERR_raise(ERR_LIB_UI, UI_R_NO_RESULT_BUFFER);
108     } else if ((ret = OPENSSL_zalloc(sizeof(*ret))) != NULL) {
109         ret->out_string = prompt;
110         ret->flags = prompt_freeable ? OUT_STRING_FREEABLE : 0;
111         ret->input_flags = input_flags;
112         ret->type = type;
113         ret->result_buf = result_buf;
114     }
115     return ret;
116 }
117 
118 static int general_allocate_string(UI *ui, const char *prompt,
119     int prompt_freeable,
120     enum UI_string_types type, int input_flags,
121     char *result_buf, int minsize, int maxsize,
122     const char *test_buf)
123 {
124     int ret = -1;
125     UI_STRING *s = general_allocate_prompt(ui, prompt, prompt_freeable,
126         type, input_flags, result_buf);
127 
128     if (s != NULL) {
129         if (allocate_string_stack(ui) >= 0) {
130             s->_.string_data.result_minsize = minsize;
131             s->_.string_data.result_maxsize = maxsize;
132             s->_.string_data.test_buf = test_buf;
133             ret = sk_UI_STRING_push(ui->strings, s);
134             /* sk_push() returns 0 on error.  Let's adapt that */
135             if (ret <= 0) {
136                 ret--;
137                 free_string(s);
138             }
139         } else
140             free_string(s);
141     }
142     return ret;
143 }
144 
145 static int general_allocate_boolean(UI *ui,
146     const char *prompt,
147     const char *action_desc,
148     const char *ok_chars,
149     const char *cancel_chars,
150     int prompt_freeable,
151     enum UI_string_types type,
152     int input_flags, char *result_buf)
153 {
154     int ret = -1;
155     UI_STRING *s;
156     const char *p;
157 
158     if (ok_chars == NULL) {
159         ERR_raise(ERR_LIB_UI, ERR_R_PASSED_NULL_PARAMETER);
160     } else if (cancel_chars == NULL) {
161         ERR_raise(ERR_LIB_UI, ERR_R_PASSED_NULL_PARAMETER);
162     } else {
163         for (p = ok_chars; *p != '\0'; p++) {
164             if (strchr(cancel_chars, *p) != NULL) {
165                 ERR_raise(ERR_LIB_UI, UI_R_COMMON_OK_AND_CANCEL_CHARACTERS);
166             }
167         }
168 
169         s = general_allocate_prompt(ui, prompt, prompt_freeable,
170             type, input_flags, result_buf);
171 
172         if (s != NULL) {
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);
178                 /*
179                  * sk_push() returns 0 on error. Let's adapt that
180                  */
181                 if (ret <= 0) {
182                     ret--;
183                     free_string(s);
184                 }
185             } else
186                 free_string(s);
187         }
188     }
189     return ret;
190 }
191 
192 /*
193  * Returns the index to the place in the stack or -1 for error.  Uses a
194  * direct reference to the prompt.
195  */
196 int UI_add_input_string(UI *ui, const char *prompt, int flags,
197     char *result_buf, int minsize, int maxsize)
198 {
199     return general_allocate_string(ui, prompt, 0,
200         UIT_PROMPT, flags, result_buf, minsize,
201         maxsize, NULL);
202 }
203 
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)
207 {
208     char *prompt_copy = NULL;
209     int ret;
210 
211     if (prompt != NULL) {
212         prompt_copy = OPENSSL_strdup(prompt);
213         if (prompt_copy == NULL)
214             return 0;
215     }
216 
217     ret = general_allocate_string(ui, prompt_copy, 1,
218         UIT_PROMPT, flags, result_buf, minsize,
219         maxsize, NULL);
220     if (ret <= 0)
221         OPENSSL_free(prompt_copy);
222 
223     return ret;
224 }
225 
226 int UI_add_verify_string(UI *ui, const char *prompt, int flags,
227     char *result_buf, int minsize, int maxsize,
228     const char *test_buf)
229 {
230     return general_allocate_string(ui, prompt, 0,
231         UIT_VERIFY, flags, result_buf, minsize,
232         maxsize, test_buf);
233 }
234 
235 int UI_dup_verify_string(UI *ui, const char *prompt, int flags,
236     char *result_buf, int minsize, int maxsize,
237     const char *test_buf)
238 {
239     char *prompt_copy = NULL;
240     int ret;
241 
242     if (prompt != NULL) {
243         prompt_copy = OPENSSL_strdup(prompt);
244         if (prompt_copy == NULL)
245             return -1;
246     }
247 
248     ret = general_allocate_string(ui, prompt_copy, 1,
249         UIT_VERIFY, flags, result_buf, minsize,
250         maxsize, test_buf);
251     if (ret <= 0)
252         OPENSSL_free(prompt_copy);
253     return ret;
254 }
255 
256 int UI_add_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)
259 {
260     return general_allocate_boolean(ui, prompt, action_desc,
261         ok_chars, cancel_chars, 0, UIT_BOOLEAN,
262         flags, result_buf);
263 }
264 
265 int UI_dup_input_boolean(UI *ui, const char *prompt, const char *action_desc,
266     const char *ok_chars, const char *cancel_chars,
267     int flags, char *result_buf)
268 {
269     char *prompt_copy = NULL;
270     char *action_desc_copy = NULL;
271     char *ok_chars_copy = NULL;
272     char *cancel_chars_copy = NULL;
273     int ret;
274 
275     if (prompt != NULL) {
276         prompt_copy = OPENSSL_strdup(prompt);
277         if (prompt_copy == NULL)
278             goto err;
279     }
280 
281     if (action_desc != NULL) {
282         action_desc_copy = OPENSSL_strdup(action_desc);
283         if (action_desc_copy == NULL)
284             goto err;
285     }
286 
287     if (ok_chars != NULL) {
288         ok_chars_copy = OPENSSL_strdup(ok_chars);
289         if (ok_chars_copy == NULL)
290             goto err;
291     }
292 
293     if (cancel_chars != NULL) {
294         cancel_chars_copy = OPENSSL_strdup(cancel_chars);
295         if (cancel_chars_copy == NULL)
296             goto err;
297     }
298 
299     ret = general_allocate_boolean(ui, prompt_copy, action_desc_copy,
300         ok_chars_copy, cancel_chars_copy, 1,
301         UIT_BOOLEAN, flags, result_buf);
302     if (ret <= 0)
303         goto err;
304 
305     return ret;
306 
307 err:
308     OPENSSL_free(prompt_copy);
309     OPENSSL_free(action_desc_copy);
310     OPENSSL_free(ok_chars_copy);
311     OPENSSL_free(cancel_chars_copy);
312     return -1;
313 }
314 
315 int UI_add_info_string(UI *ui, const char *text)
316 {
317     return general_allocate_string(ui, text, 0, UIT_INFO, 0, NULL, 0, 0,
318         NULL);
319 }
320 
321 int UI_dup_info_string(UI *ui, const char *text)
322 {
323     char *text_copy = NULL;
324     int ret;
325 
326     if (text != NULL) {
327         text_copy = OPENSSL_strdup(text);
328         if (text_copy == NULL)
329             return -1;
330     }
331 
332     ret = general_allocate_string(ui, text_copy, 1, UIT_INFO, 0, NULL,
333         0, 0, NULL);
334     if (ret <= 0)
335         OPENSSL_free(text_copy);
336     return ret;
337 }
338 
339 int UI_add_error_string(UI *ui, const char *text)
340 {
341     return general_allocate_string(ui, text, 0, UIT_ERROR, 0, NULL, 0, 0,
342         NULL);
343 }
344 
345 int UI_dup_error_string(UI *ui, const char *text)
346 {
347     char *text_copy = NULL;
348     int ret;
349 
350     if (text != NULL) {
351         text_copy = OPENSSL_strdup(text);
352         if (text_copy == NULL)
353             return -1;
354     }
355 
356     ret = general_allocate_string(ui, text_copy, 1, UIT_ERROR, 0, NULL,
357         0, 0, NULL);
358     if (ret <= 0)
359         OPENSSL_free(text_copy);
360     return ret;
361 }
362 
363 char *UI_construct_prompt(UI *ui, const char *phrase_desc,
364     const char *object_name)
365 {
366     char *prompt = NULL;
367 
368     if (ui != NULL && ui->meth != NULL && ui->meth->ui_construct_prompt != NULL)
369         prompt = ui->meth->ui_construct_prompt(ui, phrase_desc, object_name);
370     else {
371         char prompt1[] = "Enter ";
372         char prompt2[] = " for ";
373         char prompt3[] = ":";
374         int len = 0;
375 
376         if (phrase_desc == NULL)
377             return NULL;
378         len = sizeof(prompt1) - 1 + strlen(phrase_desc);
379         if (object_name != NULL)
380             len += sizeof(prompt2) - 1 + strlen(object_name);
381         len += sizeof(prompt3) - 1;
382 
383         if ((prompt = OPENSSL_malloc(len + 1)) == NULL)
384             return NULL;
385         OPENSSL_strlcpy(prompt, prompt1, len + 1);
386         OPENSSL_strlcat(prompt, phrase_desc, len + 1);
387         if (object_name != NULL) {
388             OPENSSL_strlcat(prompt, prompt2, len + 1);
389             OPENSSL_strlcat(prompt, object_name, len + 1);
390         }
391         OPENSSL_strlcat(prompt, prompt3, len + 1);
392     }
393     return prompt;
394 }
395 
396 void *UI_add_user_data(UI *ui, void *user_data)
397 {
398     void *old_data = ui->user_data;
399 
400     if ((ui->flags & UI_FLAG_DUPL_DATA) != 0) {
401         ui->meth->ui_destroy_data(ui, old_data);
402         old_data = NULL;
403     }
404     ui->user_data = user_data;
405     ui->flags &= ~UI_FLAG_DUPL_DATA;
406     return old_data;
407 }
408 
409 int UI_dup_user_data(UI *ui, void *user_data)
410 {
411     void *duplicate = NULL;
412 
413     if (ui->meth->ui_duplicate_data == NULL
414         || ui->meth->ui_destroy_data == NULL) {
415         ERR_raise(ERR_LIB_UI, UI_R_USER_DATA_DUPLICATION_UNSUPPORTED);
416         return -1;
417     }
418 
419     duplicate = ui->meth->ui_duplicate_data(ui, user_data);
420     if (duplicate == NULL) {
421         ERR_raise(ERR_LIB_UI, ERR_R_UI_LIB);
422         return -1;
423     }
424 
425     (void)UI_add_user_data(ui, duplicate);
426     ui->flags |= UI_FLAG_DUPL_DATA;
427 
428     return 0;
429 }
430 
431 void *UI_get0_user_data(UI *ui)
432 {
433     return ui->user_data;
434 }
435 
436 const char *UI_get0_result(UI *ui, int i)
437 {
438     if (i < 0) {
439         ERR_raise(ERR_LIB_UI, UI_R_INDEX_TOO_SMALL);
440         return NULL;
441     }
442     if (i >= sk_UI_STRING_num(ui->strings)) {
443         ERR_raise(ERR_LIB_UI, UI_R_INDEX_TOO_LARGE);
444         return NULL;
445     }
446     return UI_get0_result_string(sk_UI_STRING_value(ui->strings, i));
447 }
448 
449 int UI_get_result_length(UI *ui, int i)
450 {
451     if (i < 0) {
452         ERR_raise(ERR_LIB_UI, UI_R_INDEX_TOO_SMALL);
453         return -1;
454     }
455     if (i >= sk_UI_STRING_num(ui->strings)) {
456         ERR_raise(ERR_LIB_UI, UI_R_INDEX_TOO_LARGE);
457         return -1;
458     }
459     return UI_get_result_string_length(sk_UI_STRING_value(ui->strings, i));
460 }
461 
462 static int print_error(const char *str, size_t len, UI *ui)
463 {
464     UI_STRING uis;
465 
466     memset(&uis, 0, sizeof(uis));
467     uis.type = UIT_ERROR;
468     uis.out_string = str;
469 
470     if (ui->meth->ui_write_string != NULL
471         && ui->meth->ui_write_string(ui, &uis) <= 0)
472         return -1;
473     return 0;
474 }
475 
476 int UI_process(UI *ui)
477 {
478     int i, ok = 0;
479     const char *state = "processing";
480 
481     if (ui->meth->ui_open_session != NULL
482         && ui->meth->ui_open_session(ui) <= 0) {
483         state = "opening session";
484         ok = -1;
485         goto err;
486     }
487 
488     if (ui->flags & UI_FLAG_PRINT_ERRORS)
489         ERR_print_errors_cb((int (*)(const char *, size_t, void *))
490                                 print_error,
491             (void *)ui);
492 
493     for (i = 0; i < sk_UI_STRING_num(ui->strings); i++) {
494         if (ui->meth->ui_write_string != NULL
495             && (ui->meth->ui_write_string(ui,
496                     sk_UI_STRING_value(ui->strings, i))
497                 <= 0)) {
498             state = "writing strings";
499             ok = -1;
500             goto err;
501         }
502     }
503 
504     if (ui->meth->ui_flush != NULL)
505         switch (ui->meth->ui_flush(ui)) {
506         case -1: /* Interrupt/Cancel/something... */
507             ui->flags &= ~UI_FLAG_REDOABLE;
508             ok = -2;
509             goto err;
510         case 0: /* Errors */
511             state = "flushing";
512             ok = -1;
513             goto err;
514         default: /* Success */
515             ok = 0;
516             break;
517         }
518 
519     for (i = 0; i < sk_UI_STRING_num(ui->strings); i++) {
520         if (ui->meth->ui_read_string != NULL) {
521             switch (ui->meth->ui_read_string(ui,
522                 sk_UI_STRING_value(ui->strings,
523                     i))) {
524             case -1: /* Interrupt/Cancel/something... */
525                 ui->flags &= ~UI_FLAG_REDOABLE;
526                 ok = -2;
527                 goto err;
528             case 0: /* Errors */
529                 state = "reading strings";
530                 ok = -1;
531                 goto err;
532             default: /* Success */
533                 ok = 0;
534                 break;
535             }
536         } else {
537             ui->flags &= ~UI_FLAG_REDOABLE;
538             ok = -2;
539             goto err;
540         }
541     }
542 
543     state = NULL;
544 err:
545     if (ui->meth->ui_close_session != NULL
546         && ui->meth->ui_close_session(ui) <= 0) {
547         if (state == NULL)
548             state = "closing session";
549         ok = -1;
550     }
551 
552     if (ok == -1)
553         ERR_raise_data(ERR_LIB_UI, UI_R_PROCESSING_ERROR, "while %s", state);
554     return ok;
555 }
556 
557 int UI_ctrl(UI *ui, int cmd, long i, void *p, void (*f)(void))
558 {
559     if (ui == NULL) {
560         ERR_raise(ERR_LIB_UI, ERR_R_PASSED_NULL_PARAMETER);
561         return -1;
562     }
563     switch (cmd) {
564     case UI_CTRL_PRINT_ERRORS: {
565         int save_flag = !!(ui->flags & UI_FLAG_PRINT_ERRORS);
566         if (i)
567             ui->flags |= UI_FLAG_PRINT_ERRORS;
568         else
569             ui->flags &= ~UI_FLAG_PRINT_ERRORS;
570         return save_flag;
571     }
572     case UI_CTRL_IS_REDOABLE:
573         return !!(ui->flags & UI_FLAG_REDOABLE);
574     default:
575         break;
576     }
577     ERR_raise(ERR_LIB_UI, UI_R_UNKNOWN_CONTROL_COMMAND);
578     return -1;
579 }
580 
581 int UI_set_ex_data(UI *r, int idx, void *arg)
582 {
583     return CRYPTO_set_ex_data(&r->ex_data, idx, arg);
584 }
585 
586 void *UI_get_ex_data(const UI *r, int idx)
587 {
588     return CRYPTO_get_ex_data(&r->ex_data, idx);
589 }
590 
591 const UI_METHOD *UI_get_method(UI *ui)
592 {
593     return ui->meth;
594 }
595 
596 const UI_METHOD *UI_set_method(UI *ui, const UI_METHOD *meth)
597 {
598     ui->meth = meth;
599     return ui->meth;
600 }
601 
602 UI_METHOD *UI_create_method(const char *name)
603 {
604     UI_METHOD *ui_method = NULL;
605 
606     if ((ui_method = OPENSSL_zalloc(sizeof(*ui_method))) == NULL
607         || (ui_method->name = OPENSSL_strdup(name)) == NULL
608         || !CRYPTO_new_ex_data(CRYPTO_EX_INDEX_UI_METHOD, ui_method,
609             &ui_method->ex_data)) {
610 
611         if (ui_method != NULL) {
612             if (ui_method->name != NULL)
613                 /*
614                  * These conditions indicate that the CRYPTO_new_ex_data()
615                  * call failed.
616                  */
617                 ERR_raise(ERR_LIB_UI, ERR_R_CRYPTO_LIB);
618             OPENSSL_free(ui_method->name);
619         }
620         OPENSSL_free(ui_method);
621         return NULL;
622     }
623     return ui_method;
624 }
625 
626 /*
627  * BIG FSCKING WARNING!!!! If you use this on a statically allocated method
628  * (that is, it hasn't been allocated using UI_create_method(), you deserve
629  * anything Murphy can throw at you and more! You have been warned.
630  */
631 void UI_destroy_method(UI_METHOD *ui_method)
632 {
633     if (ui_method == NULL)
634         return;
635     CRYPTO_free_ex_data(CRYPTO_EX_INDEX_UI_METHOD, ui_method,
636         &ui_method->ex_data);
637     OPENSSL_free(ui_method->name);
638     ui_method->name = NULL;
639     OPENSSL_free(ui_method);
640 }
641 
642 int UI_method_set_opener(UI_METHOD *method, int (*opener)(UI *ui))
643 {
644     if (method != NULL) {
645         method->ui_open_session = opener;
646         return 0;
647     }
648     return -1;
649 }
650 
651 int UI_method_set_writer(UI_METHOD *method,
652     int (*writer)(UI *ui, UI_STRING *uis))
653 {
654     if (method != NULL) {
655         method->ui_write_string = writer;
656         return 0;
657     }
658     return -1;
659 }
660 
661 int UI_method_set_flusher(UI_METHOD *method, int (*flusher)(UI *ui))
662 {
663     if (method != NULL) {
664         method->ui_flush = flusher;
665         return 0;
666     }
667     return -1;
668 }
669 
670 int UI_method_set_reader(UI_METHOD *method,
671     int (*reader)(UI *ui, UI_STRING *uis))
672 {
673     if (method != NULL) {
674         method->ui_read_string = reader;
675         return 0;
676     }
677     return -1;
678 }
679 
680 int UI_method_set_closer(UI_METHOD *method, int (*closer)(UI *ui))
681 {
682     if (method != NULL) {
683         method->ui_close_session = closer;
684         return 0;
685     }
686     return -1;
687 }
688 
689 int UI_method_set_data_duplicator(UI_METHOD *method,
690     void *(*duplicator)(UI *ui, void *ui_data),
691     void (*destructor)(UI *ui, void *ui_data))
692 {
693     if (method != NULL) {
694         method->ui_duplicate_data = duplicator;
695         method->ui_destroy_data = destructor;
696         return 0;
697     }
698     return -1;
699 }
700 
701 int UI_method_set_prompt_constructor(UI_METHOD *method,
702     char *(*prompt_constructor)(UI *ui,
703         const char *,
704         const char *))
705 {
706     if (method != NULL) {
707         method->ui_construct_prompt = prompt_constructor;
708         return 0;
709     }
710     return -1;
711 }
712 
713 int UI_method_set_ex_data(UI_METHOD *method, int idx, void *data)
714 {
715     return CRYPTO_set_ex_data(&method->ex_data, idx, data);
716 }
717 
718 int (*UI_method_get_opener(const UI_METHOD *method))(UI *)
719 {
720     if (method != NULL)
721         return method->ui_open_session;
722     return NULL;
723 }
724 
725 int (*UI_method_get_writer(const UI_METHOD *method))(UI *, UI_STRING *)
726 {
727     if (method != NULL)
728         return method->ui_write_string;
729     return NULL;
730 }
731 
732 int (*UI_method_get_flusher(const UI_METHOD *method))(UI *)
733 {
734     if (method != NULL)
735         return method->ui_flush;
736     return NULL;
737 }
738 
739 int (*UI_method_get_reader(const UI_METHOD *method))(UI *, UI_STRING *)
740 {
741     if (method != NULL)
742         return method->ui_read_string;
743     return NULL;
744 }
745 
746 int (*UI_method_get_closer(const UI_METHOD *method))(UI *)
747 {
748     if (method != NULL)
749         return method->ui_close_session;
750     return NULL;
751 }
752 
753 char *(*UI_method_get_prompt_constructor(const UI_METHOD *method))(UI *, const char *, const char *)
754 {
755     if (method != NULL)
756         return method->ui_construct_prompt;
757     return NULL;
758 }
759 
760 void *(*UI_method_get_data_duplicator(const UI_METHOD *method))(UI *, void *)
761 {
762     if (method != NULL)
763         return method->ui_duplicate_data;
764     return NULL;
765 }
766 
767 void (*UI_method_get_data_destructor(const UI_METHOD *method))(UI *, void *)
768 {
769     if (method != NULL)
770         return method->ui_destroy_data;
771     return NULL;
772 }
773 
774 const void *UI_method_get_ex_data(const UI_METHOD *method, int idx)
775 {
776     return CRYPTO_get_ex_data(&method->ex_data, idx);
777 }
778 
779 enum UI_string_types UI_get_string_type(UI_STRING *uis)
780 {
781     return uis->type;
782 }
783 
784 int UI_get_input_flags(UI_STRING *uis)
785 {
786     return uis->input_flags;
787 }
788 
789 const char *UI_get0_output_string(UI_STRING *uis)
790 {
791     return uis->out_string;
792 }
793 
794 const char *UI_get0_action_string(UI_STRING *uis)
795 {
796     switch (uis->type) {
797     case UIT_BOOLEAN:
798         return uis->_.boolean_data.action_desc;
799     case UIT_PROMPT:
800     case UIT_NONE:
801     case UIT_VERIFY:
802     case UIT_INFO:
803     case UIT_ERROR:
804         break;
805     }
806     return NULL;
807 }
808 
809 const char *UI_get0_result_string(UI_STRING *uis)
810 {
811     switch (uis->type) {
812     case UIT_PROMPT:
813     case UIT_VERIFY:
814         return uis->result_buf;
815     case UIT_NONE:
816     case UIT_BOOLEAN:
817     case UIT_INFO:
818     case UIT_ERROR:
819         break;
820     }
821     return NULL;
822 }
823 
824 int UI_get_result_string_length(UI_STRING *uis)
825 {
826     switch (uis->type) {
827     case UIT_PROMPT:
828     case UIT_VERIFY:
829         return uis->result_len;
830     case UIT_NONE:
831     case UIT_BOOLEAN:
832     case UIT_INFO:
833     case UIT_ERROR:
834         break;
835     }
836     return -1;
837 }
838 
839 const char *UI_get0_test_string(UI_STRING *uis)
840 {
841     switch (uis->type) {
842     case UIT_VERIFY:
843         return uis->_.string_data.test_buf;
844     case UIT_NONE:
845     case UIT_BOOLEAN:
846     case UIT_INFO:
847     case UIT_ERROR:
848     case UIT_PROMPT:
849         break;
850     }
851     return NULL;
852 }
853 
854 int UI_get_result_minsize(UI_STRING *uis)
855 {
856     switch (uis->type) {
857     case UIT_PROMPT:
858     case UIT_VERIFY:
859         return uis->_.string_data.result_minsize;
860     case UIT_NONE:
861     case UIT_INFO:
862     case UIT_ERROR:
863     case UIT_BOOLEAN:
864         break;
865     }
866     return -1;
867 }
868 
869 int UI_get_result_maxsize(UI_STRING *uis)
870 {
871     switch (uis->type) {
872     case UIT_PROMPT:
873     case UIT_VERIFY:
874         return uis->_.string_data.result_maxsize;
875     case UIT_NONE:
876     case UIT_INFO:
877     case UIT_ERROR:
878     case UIT_BOOLEAN:
879         break;
880     }
881     return -1;
882 }
883 
884 int UI_set_result(UI *ui, UI_STRING *uis, const char *result)
885 {
886     return UI_set_result_ex(ui, uis, result, strlen(result));
887 }
888 
889 int UI_set_result_ex(UI *ui, UI_STRING *uis, const char *result, int len)
890 {
891     ui->flags &= ~UI_FLAG_REDOABLE;
892 
893     switch (uis->type) {
894     case UIT_PROMPT:
895     case UIT_VERIFY:
896         if (len < uis->_.string_data.result_minsize) {
897             ui->flags |= UI_FLAG_REDOABLE;
898             ERR_raise_data(ERR_LIB_UI, UI_R_RESULT_TOO_SMALL,
899                 "You must type in %d to %d characters",
900                 uis->_.string_data.result_minsize,
901                 uis->_.string_data.result_maxsize);
902             return -1;
903         }
904         if (len > uis->_.string_data.result_maxsize) {
905             ui->flags |= UI_FLAG_REDOABLE;
906             ERR_raise_data(ERR_LIB_UI, UI_R_RESULT_TOO_LARGE,
907                 "You must type in %d to %d characters",
908                 uis->_.string_data.result_minsize,
909                 uis->_.string_data.result_maxsize);
910             return -1;
911         }
912 
913         if (uis->result_buf == NULL) {
914             ERR_raise(ERR_LIB_UI, UI_R_NO_RESULT_BUFFER);
915             return -1;
916         }
917 
918         memcpy(uis->result_buf, result, len);
919         if (len <= uis->_.string_data.result_maxsize)
920             uis->result_buf[len] = '\0';
921         uis->result_len = len;
922         break;
923     case UIT_BOOLEAN: {
924         const char *p;
925 
926         if (uis->result_buf == NULL) {
927             ERR_raise(ERR_LIB_UI, UI_R_NO_RESULT_BUFFER);
928             return -1;
929         }
930 
931         uis->result_buf[0] = '\0';
932         for (p = result; *p; p++) {
933             if (strchr(uis->_.boolean_data.ok_chars, *p)) {
934                 uis->result_buf[0] = uis->_.boolean_data.ok_chars[0];
935                 break;
936             }
937             if (strchr(uis->_.boolean_data.cancel_chars, *p)) {
938                 uis->result_buf[0] = uis->_.boolean_data.cancel_chars[0];
939                 break;
940             }
941         }
942     }
943     case UIT_NONE:
944     case UIT_INFO:
945     case UIT_ERROR:
946         break;
947     }
948     return 0;
949 }
950