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