Add an application data field in the UI_METHOD
[openssl.git] / crypto / ui / ui_lib.c
1 /*
2  * Copyright 2001-2016 The OpenSSL Project Authors. All Rights Reserved.
3  *
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
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_locl.h"
17
18 static const UI_METHOD *default_UI_meth = NULL;
19
20 UI *UI_new(void)
21 {
22     return (UI_new_method(NULL));
23 }
24
25 UI *UI_new_method(const UI_METHOD *method)
26 {
27     UI *ret = OPENSSL_zalloc(sizeof(*ret));
28
29     if (ret == NULL) {
30         UIerr(UI_F_UI_NEW_METHOD, ERR_R_MALLOC_FAILURE);
31         return NULL;
32     }
33
34     ret->lock = CRYPTO_THREAD_lock_new();
35     if (ret->lock == NULL) {
36         UIerr(UI_F_UI_NEW_METHOD, ERR_R_MALLOC_FAILURE);
37         OPENSSL_free(ret);
38         return NULL;
39     }
40
41     if (method == NULL)
42         ret->meth = UI_get_default_method();
43     else
44         ret->meth = method;
45
46     if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_UI, ret, &ret->ex_data)) {
47         OPENSSL_free(ret);
48         return NULL;
49     }
50     return ret;
51 }
52
53 static void free_string(UI_STRING *uis)
54 {
55     if (uis->flags & OUT_STRING_FREEABLE) {
56         OPENSSL_free((char *)uis->out_string);
57         switch (uis->type) {
58         case UIT_BOOLEAN:
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);
62             break;
63         case UIT_NONE:
64         case UIT_PROMPT:
65         case UIT_VERIFY:
66         case UIT_ERROR:
67         case UIT_INFO:
68             break;
69         }
70     }
71     OPENSSL_free(uis);
72 }
73
74 void UI_free(UI *ui)
75 {
76     if (ui == NULL)
77         return;
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         UIerr(UI_F_GENERAL_ALLOCATE_PROMPT, ERR_R_PASSED_NULL_PARAMETER);
104     } else if ((type == UIT_PROMPT || type == UIT_VERIFY
105                 || type == UIT_BOOLEAN) && result_buf == NULL) {
106         UIerr(UI_F_GENERAL_ALLOCATE_PROMPT, UI_R_NO_RESULT_BUFFER);
107     } else if ((ret = OPENSSL_malloc(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         UIerr(UI_F_GENERAL_ALLOCATE_BOOLEAN, ERR_R_PASSED_NULL_PARAMETER);
159     } else if (cancel_chars == NULL) {
160         UIerr(UI_F_GENERAL_ALLOCATE_BOOLEAN, ERR_R_PASSED_NULL_PARAMETER);
161     } else {
162         for (p = ok_chars; *p != '\0'; p++) {
163             if (strchr(cancel_chars, *p) != NULL) {
164                 UIerr(UI_F_GENERAL_ALLOCATE_BOOLEAN,
165                       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
210     if (prompt != NULL) {
211         prompt_copy = OPENSSL_strdup(prompt);
212         if (prompt_copy == NULL) {
213             UIerr(UI_F_UI_DUP_INPUT_STRING, ERR_R_MALLOC_FAILURE);
214             return 0;
215         }
216     }
217
218     return general_allocate_string(ui, prompt_copy, 1,
219                                    UIT_PROMPT, flags, result_buf, minsize,
220                                    maxsize, NULL);
221 }
222
223 int UI_add_verify_string(UI *ui, const char *prompt, int flags,
224                          char *result_buf, int minsize, int maxsize,
225                          const char *test_buf)
226 {
227     return general_allocate_string(ui, prompt, 0,
228                                    UIT_VERIFY, flags, result_buf, minsize,
229                                    maxsize, test_buf);
230 }
231
232 int UI_dup_verify_string(UI *ui, const char *prompt, int flags,
233                          char *result_buf, int minsize, int maxsize,
234                          const char *test_buf)
235 {
236     char *prompt_copy = NULL;
237
238     if (prompt != NULL) {
239         prompt_copy = OPENSSL_strdup(prompt);
240         if (prompt_copy == NULL) {
241             UIerr(UI_F_UI_DUP_VERIFY_STRING, ERR_R_MALLOC_FAILURE);
242             return -1;
243         }
244     }
245
246     return general_allocate_string(ui, prompt_copy, 1,
247                                    UIT_VERIFY, flags, result_buf, minsize,
248                                    maxsize, test_buf);
249 }
250
251 int UI_add_input_boolean(UI *ui, const char *prompt, const char *action_desc,
252                          const char *ok_chars, const char *cancel_chars,
253                          int flags, char *result_buf)
254 {
255     return general_allocate_boolean(ui, prompt, action_desc,
256                                     ok_chars, cancel_chars, 0, UIT_BOOLEAN,
257                                     flags, result_buf);
258 }
259
260 int UI_dup_input_boolean(UI *ui, const char *prompt, const char *action_desc,
261                          const char *ok_chars, const char *cancel_chars,
262                          int flags, char *result_buf)
263 {
264     char *prompt_copy = NULL;
265     char *action_desc_copy = NULL;
266     char *ok_chars_copy = NULL;
267     char *cancel_chars_copy = NULL;
268
269     if (prompt != NULL) {
270         prompt_copy = OPENSSL_strdup(prompt);
271         if (prompt_copy == NULL) {
272             UIerr(UI_F_UI_DUP_INPUT_BOOLEAN, ERR_R_MALLOC_FAILURE);
273             goto err;
274         }
275     }
276
277     if (action_desc != NULL) {
278         action_desc_copy = OPENSSL_strdup(action_desc);
279         if (action_desc_copy == NULL) {
280             UIerr(UI_F_UI_DUP_INPUT_BOOLEAN, ERR_R_MALLOC_FAILURE);
281             goto err;
282         }
283     }
284
285     if (ok_chars != NULL) {
286         ok_chars_copy = OPENSSL_strdup(ok_chars);
287         if (ok_chars_copy == NULL) {
288             UIerr(UI_F_UI_DUP_INPUT_BOOLEAN, ERR_R_MALLOC_FAILURE);
289             goto err;
290         }
291     }
292
293     if (cancel_chars != NULL) {
294         cancel_chars_copy = OPENSSL_strdup(cancel_chars);
295         if (cancel_chars_copy == NULL) {
296             UIerr(UI_F_UI_DUP_INPUT_BOOLEAN, ERR_R_MALLOC_FAILURE);
297             goto err;
298         }
299     }
300
301     return general_allocate_boolean(ui, prompt_copy, action_desc_copy,
302                                     ok_chars_copy, cancel_chars_copy, 1,
303                                     UIT_BOOLEAN, flags, result_buf);
304  err:
305     OPENSSL_free(prompt_copy);
306     OPENSSL_free(action_desc_copy);
307     OPENSSL_free(ok_chars_copy);
308     OPENSSL_free(cancel_chars_copy);
309     return -1;
310 }
311
312 int UI_add_info_string(UI *ui, const char *text)
313 {
314     return general_allocate_string(ui, text, 0, UIT_INFO, 0, NULL, 0, 0,
315                                    NULL);
316 }
317
318 int UI_dup_info_string(UI *ui, const char *text)
319 {
320     char *text_copy = NULL;
321
322     if (text != NULL) {
323         text_copy = OPENSSL_strdup(text);
324         if (text_copy == NULL) {
325             UIerr(UI_F_UI_DUP_INFO_STRING, ERR_R_MALLOC_FAILURE);
326             return -1;
327         }
328     }
329
330     return general_allocate_string(ui, text_copy, 1, UIT_INFO, 0, NULL,
331                                    0, 0, NULL);
332 }
333
334 int UI_add_error_string(UI *ui, const char *text)
335 {
336     return general_allocate_string(ui, text, 0, UIT_ERROR, 0, NULL, 0, 0,
337                                    NULL);
338 }
339
340 int UI_dup_error_string(UI *ui, const char *text)
341 {
342     char *text_copy = NULL;
343
344     if (text != NULL) {
345         text_copy = OPENSSL_strdup(text);
346         if (text_copy == NULL) {
347             UIerr(UI_F_UI_DUP_ERROR_STRING, ERR_R_MALLOC_FAILURE);
348             return -1;
349         }
350     }
351     return general_allocate_string(ui, text_copy, 1, UIT_ERROR, 0, NULL,
352                                    0, 0, NULL);
353 }
354
355 char *UI_construct_prompt(UI *ui, const char *object_desc,
356                           const char *object_name)
357 {
358     char *prompt = NULL;
359
360     if (ui->meth->ui_construct_prompt != NULL)
361         prompt = ui->meth->ui_construct_prompt(ui, object_desc, object_name);
362     else {
363         char prompt1[] = "Enter ";
364         char prompt2[] = " for ";
365         char prompt3[] = ":";
366         int len = 0;
367
368         if (object_desc == NULL)
369             return NULL;
370         len = sizeof(prompt1) - 1 + strlen(object_desc);
371         if (object_name != NULL)
372             len += sizeof(prompt2) - 1 + strlen(object_name);
373         len += sizeof(prompt3) - 1;
374
375         prompt = OPENSSL_malloc(len + 1);
376         if (prompt == NULL)
377             return NULL;
378         OPENSSL_strlcpy(prompt, prompt1, len + 1);
379         OPENSSL_strlcat(prompt, object_desc, len + 1);
380         if (object_name != NULL) {
381             OPENSSL_strlcat(prompt, prompt2, len + 1);
382             OPENSSL_strlcat(prompt, object_name, len + 1);
383         }
384         OPENSSL_strlcat(prompt, prompt3, len + 1);
385     }
386     return prompt;
387 }
388
389 void *UI_add_user_data(UI *ui, void *user_data)
390 {
391     void *old_data = ui->user_data;
392     ui->user_data = user_data;
393     return old_data;
394 }
395
396 void *UI_get0_user_data(UI *ui)
397 {
398     return ui->user_data;
399 }
400
401 const char *UI_get0_result(UI *ui, int i)
402 {
403     if (i < 0) {
404         UIerr(UI_F_UI_GET0_RESULT, UI_R_INDEX_TOO_SMALL);
405         return NULL;
406     }
407     if (i >= sk_UI_STRING_num(ui->strings)) {
408         UIerr(UI_F_UI_GET0_RESULT, UI_R_INDEX_TOO_LARGE);
409         return NULL;
410     }
411     return UI_get0_result_string(sk_UI_STRING_value(ui->strings, i));
412 }
413
414 static int print_error(const char *str, size_t len, UI *ui)
415 {
416     UI_STRING uis;
417
418     memset(&uis, 0, sizeof(uis));
419     uis.type = UIT_ERROR;
420     uis.out_string = str;
421
422     if (ui->meth->ui_write_string != NULL
423         && ui->meth->ui_write_string(ui, &uis) <= 0)
424         return -1;
425     return 0;
426 }
427
428 int UI_process(UI *ui)
429 {
430     int i, ok = 0;
431     const char *state = "processing";
432
433     if (ui->meth->ui_open_session != NULL
434         && ui->meth->ui_open_session(ui) <= 0) {
435         state = "opening session";
436         ok = -1;
437         goto err;
438     }
439
440     if (ui->flags & UI_FLAG_PRINT_ERRORS)
441         ERR_print_errors_cb((int (*)(const char *, size_t, void *))
442                             print_error, (void *)ui);
443
444     for (i = 0; i < sk_UI_STRING_num(ui->strings); i++) {
445         if (ui->meth->ui_write_string != NULL
446             && (ui->meth->ui_write_string(ui,
447                                           sk_UI_STRING_value(ui->strings, i))
448                 <= 0))
449         {
450             state = "writing strings";
451             ok = -1;
452             goto err;
453         }
454     }
455
456     if (ui->meth->ui_flush != NULL)
457         switch (ui->meth->ui_flush(ui)) {
458         case -1:               /* Interrupt/Cancel/something... */
459             ok = -2;
460             goto err;
461         case 0:                /* Errors */
462             state = "flushing";
463             ok = -1;
464             goto err;
465         default:               /* Success */
466             ok = 0;
467             break;
468         }
469
470     for (i = 0; i < sk_UI_STRING_num(ui->strings); i++) {
471         if (ui->meth->ui_read_string != NULL) {
472             switch (ui->meth->ui_read_string(ui,
473                                              sk_UI_STRING_value(ui->strings,
474                                                                 i))) {
475             case -1:           /* Interrupt/Cancel/something... */
476                 ok = -2;
477                 goto err;
478             case 0:            /* Errors */
479                 state = "reading strings";
480                 ok = -1;
481                 goto err;
482             default:           /* Success */
483                 ok = 0;
484                 break;
485             }
486         }
487     }
488  err:
489     if (ui->meth->ui_close_session != NULL
490         && ui->meth->ui_close_session(ui) <= 0) {
491         if (state == NULL)
492             state = "closing session";
493         ok = -1;
494     }
495
496     if (ok == -1) {
497         UIerr(UI_F_UI_PROCESS, UI_R_PROCESSING_ERROR);
498         ERR_add_error_data(2, "while ", state);
499     }
500     return ok;
501 }
502
503 int UI_ctrl(UI *ui, int cmd, long i, void *p, void (*f) (void))
504 {
505     if (ui == NULL) {
506         UIerr(UI_F_UI_CTRL, ERR_R_PASSED_NULL_PARAMETER);
507         return -1;
508     }
509     switch (cmd) {
510     case UI_CTRL_PRINT_ERRORS:
511         {
512             int save_flag = ! !(ui->flags & UI_FLAG_PRINT_ERRORS);
513             if (i)
514                 ui->flags |= UI_FLAG_PRINT_ERRORS;
515             else
516                 ui->flags &= ~UI_FLAG_PRINT_ERRORS;
517             return save_flag;
518         }
519     case UI_CTRL_IS_REDOABLE:
520         return ! !(ui->flags & UI_FLAG_REDOABLE);
521     default:
522         break;
523     }
524     UIerr(UI_F_UI_CTRL, UI_R_UNKNOWN_CONTROL_COMMAND);
525     return -1;
526 }
527
528 int UI_set_ex_data(UI *r, int idx, void *arg)
529 {
530     return (CRYPTO_set_ex_data(&r->ex_data, idx, arg));
531 }
532
533 void *UI_get_ex_data(UI *r, int idx)
534 {
535     return (CRYPTO_get_ex_data(&r->ex_data, idx));
536 }
537
538 void UI_set_default_method(const UI_METHOD *meth)
539 {
540     default_UI_meth = meth;
541 }
542
543 const UI_METHOD *UI_get_default_method(void)
544 {
545     if (default_UI_meth == NULL) {
546         default_UI_meth = UI_OpenSSL();
547     }
548     return default_UI_meth;
549 }
550
551 const UI_METHOD *UI_get_method(UI *ui)
552 {
553     return ui->meth;
554 }
555
556 const UI_METHOD *UI_set_method(UI *ui, const UI_METHOD *meth)
557 {
558     ui->meth = meth;
559     return ui->meth;
560 }
561
562 UI_METHOD *UI_create_method(const char *name)
563 {
564     UI_METHOD *ui_method = NULL;
565
566     if ((ui_method = OPENSSL_zalloc(sizeof(*ui_method))) == NULL
567         || (ui_method->name = OPENSSL_strdup(name)) == NULL
568         || !CRYPTO_new_ex_data(CRYPTO_EX_INDEX_UI_METHOD, ui_method,
569                                &ui_method->ex_data)) {
570         if (ui_method)
571             OPENSSL_free(ui_method->name);
572         OPENSSL_free(ui_method);
573         UIerr(UI_F_UI_CREATE_METHOD, ERR_R_MALLOC_FAILURE);
574         return NULL;
575     }
576     return ui_method;
577 }
578
579 /*
580  * BIG FSCKING WARNING!!!! If you use this on a statically allocated method
581  * (that is, it hasn't been allocated using UI_create_method(), you deserve
582  * anything Murphy can throw at you and more! You have been warned.
583  */
584 void UI_destroy_method(UI_METHOD *ui_method)
585 {
586     if (ui_method == NULL)
587         return;
588     CRYPTO_free_ex_data(CRYPTO_EX_INDEX_UI_METHOD, ui_method,
589                         &ui_method->ex_data);
590     OPENSSL_free(ui_method->name);
591     ui_method->name = NULL;
592     OPENSSL_free(ui_method);
593 }
594
595 int UI_method_set_opener(UI_METHOD *method, int (*opener) (UI *ui))
596 {
597     if (method != NULL) {
598         method->ui_open_session = opener;
599         return 0;
600     }
601     return -1;
602 }
603
604 int UI_method_set_writer(UI_METHOD *method,
605                          int (*writer) (UI *ui, UI_STRING *uis))
606 {
607     if (method != NULL) {
608         method->ui_write_string = writer;
609         return 0;
610     }
611     return -1;
612 }
613
614 int UI_method_set_flusher(UI_METHOD *method, int (*flusher) (UI *ui))
615 {
616     if (method != NULL) {
617         method->ui_flush = flusher;
618         return 0;
619     }
620     return -1;
621 }
622
623 int UI_method_set_reader(UI_METHOD *method,
624                          int (*reader) (UI *ui, UI_STRING *uis))
625 {
626     if (method != NULL) {
627         method->ui_read_string = reader;
628         return 0;
629     }
630     return -1;
631 }
632
633 int UI_method_set_closer(UI_METHOD *method, int (*closer) (UI *ui))
634 {
635     if (method != NULL) {
636         method->ui_close_session = closer;
637         return 0;
638     }
639     return -1;
640 }
641
642 int UI_method_set_prompt_constructor(UI_METHOD *method,
643                                      char *(*prompt_constructor) (UI *ui,
644                                                                   const char
645                                                                   *object_desc,
646                                                                   const char
647                                                                   *object_name))
648 {
649     if (method != NULL) {
650         method->ui_construct_prompt = prompt_constructor;
651         return 0;
652     }
653     return -1;
654 }
655
656 int UI_method_set_ex_data(UI_METHOD *method, int idx, void *data)
657 {
658     return CRYPTO_set_ex_data(&method->ex_data, idx, data);
659 }
660
661 int (*UI_method_get_opener(const UI_METHOD *method)) (UI *)
662 {
663     if (method != NULL)
664         return method->ui_open_session;
665     return NULL;
666 }
667
668 int (*UI_method_get_writer(const UI_METHOD *method)) (UI *, UI_STRING *)
669 {
670     if (method != NULL)
671         return method->ui_write_string;
672     return NULL;
673 }
674
675 int (*UI_method_get_flusher(const UI_METHOD *method)) (UI *)
676 {
677     if (method != NULL)
678         return method->ui_flush;
679     return NULL;
680 }
681
682 int (*UI_method_get_reader(const UI_METHOD *method)) (UI *, UI_STRING *)
683 {
684     if (method != NULL)
685         return method->ui_read_string;
686     return NULL;
687 }
688
689 int (*UI_method_get_closer(const UI_METHOD *method)) (UI *)
690 {
691     if (method != NULL)
692         return method->ui_close_session;
693     return NULL;
694 }
695
696 char *(*UI_method_get_prompt_constructor(const UI_METHOD *method))
697     (UI *, const char *, const char *)
698 {
699     if (method != NULL)
700         return method->ui_construct_prompt;
701     return NULL;
702 }
703
704 const void *UI_method_get_ex_data(const UI_METHOD *method, int idx)
705 {
706     return CRYPTO_get_ex_data(&method->ex_data, idx);
707 }
708
709 enum UI_string_types UI_get_string_type(UI_STRING *uis)
710 {
711     return uis->type;
712 }
713
714 int UI_get_input_flags(UI_STRING *uis)
715 {
716     return uis->input_flags;
717 }
718
719 const char *UI_get0_output_string(UI_STRING *uis)
720 {
721     return uis->out_string;
722 }
723
724 const char *UI_get0_action_string(UI_STRING *uis)
725 {
726     switch (uis->type) {
727     case UIT_PROMPT:
728     case UIT_BOOLEAN:
729         return uis->_.boolean_data.action_desc;
730     case UIT_NONE:
731     case UIT_VERIFY:
732     case UIT_INFO:
733     case UIT_ERROR:
734         break;
735     }
736     return NULL;
737 }
738
739 const char *UI_get0_result_string(UI_STRING *uis)
740 {
741     switch (uis->type) {
742     case UIT_PROMPT:
743     case UIT_VERIFY:
744         return uis->result_buf;
745     case UIT_NONE:
746     case UIT_BOOLEAN:
747     case UIT_INFO:
748     case UIT_ERROR:
749         break;
750     }
751     return NULL;
752 }
753
754 const char *UI_get0_test_string(UI_STRING *uis)
755 {
756     switch (uis->type) {
757     case UIT_VERIFY:
758         return uis->_.string_data.test_buf;
759     case UIT_NONE:
760     case UIT_BOOLEAN:
761     case UIT_INFO:
762     case UIT_ERROR:
763     case UIT_PROMPT:
764         break;
765     }
766     return NULL;
767 }
768
769 int UI_get_result_minsize(UI_STRING *uis)
770 {
771     switch (uis->type) {
772     case UIT_PROMPT:
773     case UIT_VERIFY:
774         return uis->_.string_data.result_minsize;
775     case UIT_NONE:
776     case UIT_INFO:
777     case UIT_ERROR:
778     case UIT_BOOLEAN:
779         break;
780     }
781     return -1;
782 }
783
784 int UI_get_result_maxsize(UI_STRING *uis)
785 {
786     switch (uis->type) {
787     case UIT_PROMPT:
788     case UIT_VERIFY:
789         return uis->_.string_data.result_maxsize;
790     case UIT_NONE:
791     case UIT_INFO:
792     case UIT_ERROR:
793     case UIT_BOOLEAN:
794         break;
795     }
796     return -1;
797 }
798
799 int UI_set_result(UI *ui, UI_STRING *uis, const char *result)
800 {
801     int l = strlen(result);
802
803     ui->flags &= ~UI_FLAG_REDOABLE;
804
805     switch (uis->type) {
806     case UIT_PROMPT:
807     case UIT_VERIFY:
808         {
809             char number1[DECIMAL_SIZE(uis->_.string_data.result_minsize) + 1];
810             char number2[DECIMAL_SIZE(uis->_.string_data.result_maxsize) + 1];
811
812             BIO_snprintf(number1, sizeof(number1), "%d",
813                          uis->_.string_data.result_minsize);
814             BIO_snprintf(number2, sizeof(number2), "%d",
815                          uis->_.string_data.result_maxsize);
816
817             if (l < uis->_.string_data.result_minsize) {
818                 ui->flags |= UI_FLAG_REDOABLE;
819                 UIerr(UI_F_UI_SET_RESULT, UI_R_RESULT_TOO_SMALL);
820                 ERR_add_error_data(5, "You must type in ",
821                                    number1, " to ", number2, " characters");
822                 return -1;
823             }
824             if (l > uis->_.string_data.result_maxsize) {
825                 ui->flags |= UI_FLAG_REDOABLE;
826                 UIerr(UI_F_UI_SET_RESULT, UI_R_RESULT_TOO_LARGE);
827                 ERR_add_error_data(5, "You must type in ",
828                                    number1, " to ", number2, " characters");
829                 return -1;
830             }
831         }
832
833         if (uis->result_buf == NULL) {
834             UIerr(UI_F_UI_SET_RESULT, UI_R_NO_RESULT_BUFFER);
835             return -1;
836         }
837
838         OPENSSL_strlcpy(uis->result_buf, result,
839                     uis->_.string_data.result_maxsize + 1);
840         break;
841     case UIT_BOOLEAN:
842         {
843             const char *p;
844
845             if (uis->result_buf == NULL) {
846                 UIerr(UI_F_UI_SET_RESULT, UI_R_NO_RESULT_BUFFER);
847                 return -1;
848             }
849
850             uis->result_buf[0] = '\0';
851             for (p = result; *p; p++) {
852                 if (strchr(uis->_.boolean_data.ok_chars, *p)) {
853                     uis->result_buf[0] = uis->_.boolean_data.ok_chars[0];
854                     break;
855                 }
856                 if (strchr(uis->_.boolean_data.cancel_chars, *p)) {
857                     uis->result_buf[0] = uis->_.boolean_data.cancel_chars[0];
858                     break;
859                 }
860             }
861         }
862     case UIT_NONE:
863     case UIT_INFO:
864     case UIT_ERROR:
865         break;
866     }
867     return 0;
868 }