a8756af1cdeabbfb93b63b88fb5c523d1fb02ad7
[openssl.git] / crypto / ui / ui_lib.c
1 /*
2  * Copyright 2001-2023 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) && 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;
111         ret->type = type;
112         ret->result_buf = result_buf;
113     }
114     return ret;
115 }
116
117 static int general_allocate_string(UI *ui, const char *prompt,
118                                    int prompt_freeable,
119                                    enum UI_string_types type, int input_flags,
120                                    char *result_buf, int minsize, int maxsize,
121                                    const char *test_buf)
122 {
123     int ret = -1;
124     UI_STRING *s = general_allocate_prompt(ui, prompt, prompt_freeable,
125                                            type, input_flags, result_buf);
126
127     if (s != NULL) {
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 */
134             if (ret <= 0) {
135                 ret--;
136                 free_string(s);
137             }
138         } else
139             free_string(s);
140     }
141     return ret;
142 }
143
144 static int general_allocate_boolean(UI *ui,
145                                     const char *prompt,
146                                     const char *action_desc,
147                                     const char *ok_chars,
148                                     const char *cancel_chars,
149                                     int prompt_freeable,
150                                     enum UI_string_types type,
151                                     int input_flags, char *result_buf)
152 {
153     int ret = -1;
154     UI_STRING *s;
155     const char *p;
156
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);
161     } else {
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);
165             }
166         }
167
168         s = general_allocate_prompt(ui, prompt, prompt_freeable,
169                                     type, input_flags, result_buf);
170
171         if (s != NULL) {
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);
177                 /*
178                  * sk_push() returns 0 on error. Let's adapt that
179                  */
180                 if (ret <= 0) {
181                     ret--;
182                     free_string(s);
183                 }
184             } else
185                 free_string(s);
186         }
187     }
188     return ret;
189 }
190
191 /*
192  * Returns the index to the place in the stack or -1 for error.  Uses a
193  * direct reference to the prompt.
194  */
195 int UI_add_input_string(UI *ui, const char *prompt, int flags,
196                         char *result_buf, int minsize, int maxsize)
197 {
198     return general_allocate_string(ui, prompt, 0,
199                                    UIT_PROMPT, flags, result_buf, minsize,
200                                    maxsize, NULL);
201 }
202
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)
206 {
207     char *prompt_copy = NULL;
208
209     if (prompt != NULL) {
210         prompt_copy = OPENSSL_strdup(prompt);
211         if (prompt_copy == NULL)
212             return 0;
213     }
214
215     return general_allocate_string(ui, prompt_copy, 1,
216                                    UIT_PROMPT, flags, result_buf, minsize,
217                                    maxsize, NULL);
218 }
219
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)
223 {
224     return general_allocate_string(ui, prompt, 0,
225                                    UIT_VERIFY, flags, result_buf, minsize,
226                                    maxsize, test_buf);
227 }
228
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)
232 {
233     char *prompt_copy = NULL;
234
235     if (prompt != NULL) {
236         prompt_copy = OPENSSL_strdup(prompt);
237         if (prompt_copy == NULL)
238             return -1;
239     }
240
241     return general_allocate_string(ui, prompt_copy, 1,
242                                    UIT_VERIFY, flags, result_buf, minsize,
243                                    maxsize, test_buf);
244 }
245
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)
249 {
250     return general_allocate_boolean(ui, prompt, action_desc,
251                                     ok_chars, cancel_chars, 0, UIT_BOOLEAN,
252                                     flags, result_buf);
253 }
254
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)
258 {
259     char *prompt_copy = NULL;
260     char *action_desc_copy = NULL;
261     char *ok_chars_copy = NULL;
262     char *cancel_chars_copy = NULL;
263
264     if (prompt != NULL) {
265         prompt_copy = OPENSSL_strdup(prompt);
266         if (prompt_copy == NULL)
267             goto err;
268     }
269
270     if (action_desc != NULL) {
271         action_desc_copy = OPENSSL_strdup(action_desc);
272         if (action_desc_copy == NULL)
273             goto err;
274     }
275
276     if (ok_chars != NULL) {
277         ok_chars_copy = OPENSSL_strdup(ok_chars);
278         if (ok_chars_copy == NULL)
279             goto err;
280     }
281
282     if (cancel_chars != NULL) {
283         cancel_chars_copy = OPENSSL_strdup(cancel_chars);
284         if (cancel_chars_copy == NULL)
285             goto err;
286     }
287
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);
291  err:
292     OPENSSL_free(prompt_copy);
293     OPENSSL_free(action_desc_copy);
294     OPENSSL_free(ok_chars_copy);
295     OPENSSL_free(cancel_chars_copy);
296     return -1;
297 }
298
299 int UI_add_info_string(UI *ui, const char *text)
300 {
301     return general_allocate_string(ui, text, 0, UIT_INFO, 0, NULL, 0, 0,
302                                    NULL);
303 }
304
305 int UI_dup_info_string(UI *ui, const char *text)
306 {
307     char *text_copy = NULL;
308
309     if (text != NULL) {
310         text_copy = OPENSSL_strdup(text);
311         if (text_copy == NULL)
312             return -1;
313     }
314
315     return general_allocate_string(ui, text_copy, 1, UIT_INFO, 0, NULL,
316                                    0, 0, NULL);
317 }
318
319 int UI_add_error_string(UI *ui, const char *text)
320 {
321     return general_allocate_string(ui, text, 0, UIT_ERROR, 0, NULL, 0, 0,
322                                    NULL);
323 }
324
325 int UI_dup_error_string(UI *ui, const char *text)
326 {
327     char *text_copy = NULL;
328
329     if (text != NULL) {
330         text_copy = OPENSSL_strdup(text);
331         if (text_copy == NULL)
332             return -1;
333     }
334     return general_allocate_string(ui, text_copy, 1, UIT_ERROR, 0, NULL,
335                                    0, 0, NULL);
336 }
337
338 char *UI_construct_prompt(UI *ui, const char *phrase_desc,
339                           const char *object_name)
340 {
341     char *prompt = NULL;
342
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);
345     else {
346         char prompt1[] = "Enter ";
347         char prompt2[] = " for ";
348         char prompt3[] = ":";
349         int len = 0;
350
351         if (phrase_desc == NULL)
352             return 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;
357
358         if ((prompt = OPENSSL_malloc(len + 1)) == NULL)
359             return 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);
365         }
366         OPENSSL_strlcat(prompt, prompt3, len + 1);
367     }
368     return prompt;
369 }
370
371 void *UI_add_user_data(UI *ui, void *user_data)
372 {
373     void *old_data = ui->user_data;
374
375     if ((ui->flags & UI_FLAG_DUPL_DATA) != 0) {
376         ui->meth->ui_destroy_data(ui, old_data);
377         old_data = NULL;
378     }
379     ui->user_data = user_data;
380     ui->flags &= ~UI_FLAG_DUPL_DATA;
381     return old_data;
382 }
383
384 int UI_dup_user_data(UI *ui, void *user_data)
385 {
386     void *duplicate = NULL;
387
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);
391         return -1;
392     }
393
394     duplicate = ui->meth->ui_duplicate_data(ui, user_data);
395     if (duplicate == NULL) {
396         ERR_raise(ERR_LIB_UI, ERR_R_UI_LIB);
397         return -1;
398     }
399
400     (void)UI_add_user_data(ui, duplicate);
401     ui->flags |= UI_FLAG_DUPL_DATA;
402
403     return 0;
404 }
405
406 void *UI_get0_user_data(UI *ui)
407 {
408     return ui->user_data;
409 }
410
411 const char *UI_get0_result(UI *ui, int i)
412 {
413     if (i < 0) {
414         ERR_raise(ERR_LIB_UI, UI_R_INDEX_TOO_SMALL);
415         return NULL;
416     }
417     if (i >= sk_UI_STRING_num(ui->strings)) {
418         ERR_raise(ERR_LIB_UI, UI_R_INDEX_TOO_LARGE);
419         return NULL;
420     }
421     return UI_get0_result_string(sk_UI_STRING_value(ui->strings, i));
422 }
423
424 int UI_get_result_length(UI *ui, int i)
425 {
426     if (i < 0) {
427         ERR_raise(ERR_LIB_UI, UI_R_INDEX_TOO_SMALL);
428         return -1;
429     }
430     if (i >= sk_UI_STRING_num(ui->strings)) {
431         ERR_raise(ERR_LIB_UI, UI_R_INDEX_TOO_LARGE);
432         return -1;
433     }
434     return UI_get_result_string_length(sk_UI_STRING_value(ui->strings, i));
435 }
436
437 static int print_error(const char *str, size_t len, UI *ui)
438 {
439     UI_STRING uis;
440
441     memset(&uis, 0, sizeof(uis));
442     uis.type = UIT_ERROR;
443     uis.out_string = str;
444
445     if (ui->meth->ui_write_string != NULL
446         && ui->meth->ui_write_string(ui, &uis) <= 0)
447         return -1;
448     return 0;
449 }
450
451 int UI_process(UI *ui)
452 {
453     int i, ok = 0;
454     const char *state = "processing";
455
456     if (ui->meth->ui_open_session != NULL
457         && ui->meth->ui_open_session(ui) <= 0) {
458         state = "opening session";
459         ok = -1;
460         goto err;
461     }
462
463     if (ui->flags & UI_FLAG_PRINT_ERRORS)
464         ERR_print_errors_cb((int (*)(const char *, size_t, void *))
465                             print_error, (void *)ui);
466
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))
471                 <= 0))
472         {
473             state = "writing strings";
474             ok = -1;
475             goto err;
476         }
477     }
478
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;
483             ok = -2;
484             goto err;
485         case 0:                /* Errors */
486             state = "flushing";
487             ok = -1;
488             goto err;
489         default:               /* Success */
490             ok = 0;
491             break;
492         }
493
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,
498                                                                 i))) {
499             case -1:           /* Interrupt/Cancel/something... */
500                 ui->flags &= ~UI_FLAG_REDOABLE;
501                 ok = -2;
502                 goto err;
503             case 0:            /* Errors */
504                 state = "reading strings";
505                 ok = -1;
506                 goto err;
507             default:           /* Success */
508                 ok = 0;
509                 break;
510             }
511         } else {
512             ui->flags &= ~UI_FLAG_REDOABLE;
513             ok = -2;
514             goto err;
515         }
516     }
517
518     state = NULL;
519  err:
520     if (ui->meth->ui_close_session != NULL
521         && ui->meth->ui_close_session(ui) <= 0) {
522         if (state == NULL)
523             state = "closing session";
524         ok = -1;
525     }
526
527     if (ok == -1)
528         ERR_raise_data(ERR_LIB_UI, UI_R_PROCESSING_ERROR, "while %s", state);
529     return ok;
530 }
531
532 int UI_ctrl(UI *ui, int cmd, long i, void *p, void (*f) (void))
533 {
534     if (ui == NULL) {
535         ERR_raise(ERR_LIB_UI, ERR_R_PASSED_NULL_PARAMETER);
536         return -1;
537     }
538     switch (cmd) {
539     case UI_CTRL_PRINT_ERRORS:
540         {
541             int save_flag = ! !(ui->flags & UI_FLAG_PRINT_ERRORS);
542             if (i)
543                 ui->flags |= UI_FLAG_PRINT_ERRORS;
544             else
545                 ui->flags &= ~UI_FLAG_PRINT_ERRORS;
546             return save_flag;
547         }
548     case UI_CTRL_IS_REDOABLE:
549         return ! !(ui->flags & UI_FLAG_REDOABLE);
550     default:
551         break;
552     }
553     ERR_raise(ERR_LIB_UI, UI_R_UNKNOWN_CONTROL_COMMAND);
554     return -1;
555 }
556
557 int UI_set_ex_data(UI *r, int idx, void *arg)
558 {
559     return CRYPTO_set_ex_data(&r->ex_data, idx, arg);
560 }
561
562 void *UI_get_ex_data(const UI *r, int idx)
563 {
564     return CRYPTO_get_ex_data(&r->ex_data, idx);
565 }
566
567 const UI_METHOD *UI_get_method(UI *ui)
568 {
569     return ui->meth;
570 }
571
572 const UI_METHOD *UI_set_method(UI *ui, const UI_METHOD *meth)
573 {
574     ui->meth = meth;
575     return ui->meth;
576 }
577
578 UI_METHOD *UI_create_method(const char *name)
579 {
580     UI_METHOD *ui_method = NULL;
581
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)) {
586
587         if (ui_method != NULL) {
588             if (ui_method->name != NULL)
589                 /*
590                  * These conditions indicate that the CRYPTO_new_ex_data()
591                  * call failed.
592                  */
593                 ERR_raise(ERR_LIB_UI, ERR_R_CRYPTO_LIB);
594             OPENSSL_free(ui_method->name);
595         }
596         OPENSSL_free(ui_method);
597         return NULL;
598     }
599     return ui_method;
600 }
601
602 /*
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.
606  */
607 void UI_destroy_method(UI_METHOD *ui_method)
608 {
609     if (ui_method == NULL)
610         return;
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);
616 }
617
618 int UI_method_set_opener(UI_METHOD *method, int (*opener) (UI *ui))
619 {
620     if (method != NULL) {
621         method->ui_open_session = opener;
622         return 0;
623     }
624     return -1;
625 }
626
627 int UI_method_set_writer(UI_METHOD *method,
628                          int (*writer) (UI *ui, UI_STRING *uis))
629 {
630     if (method != NULL) {
631         method->ui_write_string = writer;
632         return 0;
633     }
634     return -1;
635 }
636
637 int UI_method_set_flusher(UI_METHOD *method, int (*flusher) (UI *ui))
638 {
639     if (method != NULL) {
640         method->ui_flush = flusher;
641         return 0;
642     }
643     return -1;
644 }
645
646 int UI_method_set_reader(UI_METHOD *method,
647                          int (*reader) (UI *ui, UI_STRING *uis))
648 {
649     if (method != NULL) {
650         method->ui_read_string = reader;
651         return 0;
652     }
653     return -1;
654 }
655
656 int UI_method_set_closer(UI_METHOD *method, int (*closer) (UI *ui))
657 {
658     if (method != NULL) {
659         method->ui_close_session = closer;
660         return 0;
661     }
662     return -1;
663 }
664
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))
668 {
669     if (method != NULL) {
670         method->ui_duplicate_data = duplicator;
671         method->ui_destroy_data = destructor;
672         return 0;
673     }
674     return -1;
675 }
676
677 int UI_method_set_prompt_constructor(UI_METHOD *method,
678                                      char *(*prompt_constructor) (UI *ui,
679                                                                   const char *,
680                                                                   const char *))
681 {
682     if (method != NULL) {
683         method->ui_construct_prompt = prompt_constructor;
684         return 0;
685     }
686     return -1;
687 }
688
689 int UI_method_set_ex_data(UI_METHOD *method, int idx, void *data)
690 {
691     return CRYPTO_set_ex_data(&method->ex_data, idx, data);
692 }
693
694 int (*UI_method_get_opener(const UI_METHOD *method)) (UI *)
695 {
696     if (method != NULL)
697         return method->ui_open_session;
698     return NULL;
699 }
700
701 int (*UI_method_get_writer(const UI_METHOD *method)) (UI *, UI_STRING *)
702 {
703     if (method != NULL)
704         return method->ui_write_string;
705     return NULL;
706 }
707
708 int (*UI_method_get_flusher(const UI_METHOD *method)) (UI *)
709 {
710     if (method != NULL)
711         return method->ui_flush;
712     return NULL;
713 }
714
715 int (*UI_method_get_reader(const UI_METHOD *method)) (UI *, UI_STRING *)
716 {
717     if (method != NULL)
718         return method->ui_read_string;
719     return NULL;
720 }
721
722 int (*UI_method_get_closer(const UI_METHOD *method)) (UI *)
723 {
724     if (method != NULL)
725         return method->ui_close_session;
726     return NULL;
727 }
728
729 char *(*UI_method_get_prompt_constructor(const UI_METHOD *method))
730     (UI *, const char *, const char *)
731 {
732     if (method != NULL)
733         return method->ui_construct_prompt;
734     return NULL;
735 }
736
737 void *(*UI_method_get_data_duplicator(const UI_METHOD *method)) (UI *, void *)
738 {
739     if (method != NULL)
740         return method->ui_duplicate_data;
741     return NULL;
742 }
743
744 void (*UI_method_get_data_destructor(const UI_METHOD *method)) (UI *, void *)
745 {
746     if (method != NULL)
747         return method->ui_destroy_data;
748     return NULL;
749 }
750
751 const void *UI_method_get_ex_data(const UI_METHOD *method, int idx)
752 {
753     return CRYPTO_get_ex_data(&method->ex_data, idx);
754 }
755
756 enum UI_string_types UI_get_string_type(UI_STRING *uis)
757 {
758     return uis->type;
759 }
760
761 int UI_get_input_flags(UI_STRING *uis)
762 {
763     return uis->input_flags;
764 }
765
766 const char *UI_get0_output_string(UI_STRING *uis)
767 {
768     return uis->out_string;
769 }
770
771 const char *UI_get0_action_string(UI_STRING *uis)
772 {
773     switch (uis->type) {
774     case UIT_BOOLEAN:
775         return uis->_.boolean_data.action_desc;
776     case UIT_PROMPT:
777     case UIT_NONE:
778     case UIT_VERIFY:
779     case UIT_INFO:
780     case UIT_ERROR:
781         break;
782     }
783     return NULL;
784 }
785
786 const char *UI_get0_result_string(UI_STRING *uis)
787 {
788     switch (uis->type) {
789     case UIT_PROMPT:
790     case UIT_VERIFY:
791         return uis->result_buf;
792     case UIT_NONE:
793     case UIT_BOOLEAN:
794     case UIT_INFO:
795     case UIT_ERROR:
796         break;
797     }
798     return NULL;
799 }
800
801 int UI_get_result_string_length(UI_STRING *uis)
802 {
803     switch (uis->type) {
804     case UIT_PROMPT:
805     case UIT_VERIFY:
806         return uis->result_len;
807     case UIT_NONE:
808     case UIT_BOOLEAN:
809     case UIT_INFO:
810     case UIT_ERROR:
811         break;
812     }
813     return -1;
814 }
815
816 const char *UI_get0_test_string(UI_STRING *uis)
817 {
818     switch (uis->type) {
819     case UIT_VERIFY:
820         return uis->_.string_data.test_buf;
821     case UIT_NONE:
822     case UIT_BOOLEAN:
823     case UIT_INFO:
824     case UIT_ERROR:
825     case UIT_PROMPT:
826         break;
827     }
828     return NULL;
829 }
830
831 int UI_get_result_minsize(UI_STRING *uis)
832 {
833     switch (uis->type) {
834     case UIT_PROMPT:
835     case UIT_VERIFY:
836         return uis->_.string_data.result_minsize;
837     case UIT_NONE:
838     case UIT_INFO:
839     case UIT_ERROR:
840     case UIT_BOOLEAN:
841         break;
842     }
843     return -1;
844 }
845
846 int UI_get_result_maxsize(UI_STRING *uis)
847 {
848     switch (uis->type) {
849     case UIT_PROMPT:
850     case UIT_VERIFY:
851         return uis->_.string_data.result_maxsize;
852     case UIT_NONE:
853     case UIT_INFO:
854     case UIT_ERROR:
855     case UIT_BOOLEAN:
856         break;
857     }
858     return -1;
859 }
860
861 int UI_set_result(UI *ui, UI_STRING *uis, const char *result)
862 {
863     return UI_set_result_ex(ui, uis, result, strlen(result));
864 }
865
866 int UI_set_result_ex(UI *ui, UI_STRING *uis, const char *result, int len)
867 {
868     ui->flags &= ~UI_FLAG_REDOABLE;
869
870     switch (uis->type) {
871     case UIT_PROMPT:
872     case UIT_VERIFY:
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);
879             return -1;
880         }
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);
887             return -1;
888         }
889
890         if (uis->result_buf == NULL) {
891             ERR_raise(ERR_LIB_UI, UI_R_NO_RESULT_BUFFER);
892             return -1;
893         }
894
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;
899         break;
900     case UIT_BOOLEAN:
901         {
902             const char *p;
903
904             if (uis->result_buf == NULL) {
905                 ERR_raise(ERR_LIB_UI, UI_R_NO_RESULT_BUFFER);
906                 return -1;
907             }
908
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];
913                     break;
914                 }
915                 if (strchr(uis->_.boolean_data.cancel_chars, *p)) {
916                     uis->result_buf[0] = uis->_.boolean_data.cancel_chars[0];
917                     break;
918                 }
919             }
920         }
921     case UIT_NONE:
922     case UIT_INFO:
923     case UIT_ERROR:
924         break;
925     }
926     return 0;
927 }