UI_process() didn't generate errors
[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) {
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; p++) {
163             if (strchr(cancel_chars, *p)) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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)
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)
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) {
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 && !ui->meth->ui_write_string(ui, &uis))
423         return -1;
424     return 0;
425 }
426
427 int UI_process(UI *ui)
428 {
429     int i, ok = 0;
430     const char *state = "processing";
431
432     if (ui->meth->ui_open_session && !ui->meth->ui_open_session(ui)) {
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
444             && !ui->meth->ui_write_string(ui,
445                                           sk_UI_STRING_value(ui->strings, i)))
446         {
447             state = "writing strings";
448             ok = -1;
449             goto err;
450         }
451     }
452
453     if (ui->meth->ui_flush)
454         switch (ui->meth->ui_flush(ui)) {
455         case -1:               /* Interrupt/Cancel/something... */
456             ok = -2;
457             goto err;
458         case 0:                /* Errors */
459             state = "flushing";
460             ok = -1;
461             goto err;
462         default:               /* Success */
463             ok = 0;
464             break;
465         }
466
467     for (i = 0; i < sk_UI_STRING_num(ui->strings); i++) {
468         if (ui->meth->ui_read_string) {
469             switch (ui->meth->ui_read_string(ui,
470                                              sk_UI_STRING_value(ui->strings,
471                                                                 i))) {
472             case -1:           /* Interrupt/Cancel/something... */
473                 ok = -2;
474                 goto err;
475             case 0:            /* Errors */
476                 state = "reading strings";
477                 ok = -1;
478                 goto err;
479             default:           /* Success */
480                 ok = 0;
481                 break;
482             }
483         }
484     }
485  err:
486     if (ui->meth->ui_close_session && !ui->meth->ui_close_session(ui)) {
487         if (state == NULL)
488             state = "closing session";
489         ok = -1;
490     }
491
492     if (ok == -1) {
493         UIerr(UI_F_UI_PROCESS, UI_R_PROCESSING_ERROR);
494         ERR_add_error_data(2, "while ", state);
495     }
496     return ok;
497 }
498
499 int UI_ctrl(UI *ui, int cmd, long i, void *p, void (*f) (void))
500 {
501     if (ui == NULL) {
502         UIerr(UI_F_UI_CTRL, ERR_R_PASSED_NULL_PARAMETER);
503         return -1;
504     }
505     switch (cmd) {
506     case UI_CTRL_PRINT_ERRORS:
507         {
508             int save_flag = ! !(ui->flags & UI_FLAG_PRINT_ERRORS);
509             if (i)
510                 ui->flags |= UI_FLAG_PRINT_ERRORS;
511             else
512                 ui->flags &= ~UI_FLAG_PRINT_ERRORS;
513             return save_flag;
514         }
515     case UI_CTRL_IS_REDOABLE:
516         return ! !(ui->flags & UI_FLAG_REDOABLE);
517     default:
518         break;
519     }
520     UIerr(UI_F_UI_CTRL, UI_R_UNKNOWN_CONTROL_COMMAND);
521     return -1;
522 }
523
524 int UI_set_ex_data(UI *r, int idx, void *arg)
525 {
526     return (CRYPTO_set_ex_data(&r->ex_data, idx, arg));
527 }
528
529 void *UI_get_ex_data(UI *r, int idx)
530 {
531     return (CRYPTO_get_ex_data(&r->ex_data, idx));
532 }
533
534 void UI_set_default_method(const UI_METHOD *meth)
535 {
536     default_UI_meth = meth;
537 }
538
539 const UI_METHOD *UI_get_default_method(void)
540 {
541     if (default_UI_meth == NULL) {
542         default_UI_meth = UI_OpenSSL();
543     }
544     return default_UI_meth;
545 }
546
547 const UI_METHOD *UI_get_method(UI *ui)
548 {
549     return ui->meth;
550 }
551
552 const UI_METHOD *UI_set_method(UI *ui, const UI_METHOD *meth)
553 {
554     ui->meth = meth;
555     return ui->meth;
556 }
557
558 UI_METHOD *UI_create_method(const char *name)
559 {
560     UI_METHOD *ui_method = OPENSSL_zalloc(sizeof(*ui_method));
561
562     if (ui_method != NULL) {
563         ui_method->name = OPENSSL_strdup(name);
564         if (ui_method->name == NULL) {
565             OPENSSL_free(ui_method);
566             UIerr(UI_F_UI_CREATE_METHOD, ERR_R_MALLOC_FAILURE);
567             return NULL;
568         }
569     }
570     return ui_method;
571 }
572
573 /*
574  * BIG FSCKING WARNING!!!! If you use this on a statically allocated method
575  * (that is, it hasn't been allocated using UI_create_method(), you deserve
576  * anything Murphy can throw at you and more! You have been warned.
577  */
578 void UI_destroy_method(UI_METHOD *ui_method)
579 {
580     OPENSSL_free(ui_method->name);
581     ui_method->name = NULL;
582     OPENSSL_free(ui_method);
583 }
584
585 int UI_method_set_opener(UI_METHOD *method, int (*opener) (UI *ui))
586 {
587     if (method) {
588         method->ui_open_session = opener;
589         return 0;
590     } else
591         return -1;
592 }
593
594 int UI_method_set_writer(UI_METHOD *method,
595                          int (*writer) (UI *ui, UI_STRING *uis))
596 {
597     if (method) {
598         method->ui_write_string = writer;
599         return 0;
600     } else
601         return -1;
602 }
603
604 int UI_method_set_flusher(UI_METHOD *method, int (*flusher) (UI *ui))
605 {
606     if (method) {
607         method->ui_flush = flusher;
608         return 0;
609     } else
610         return -1;
611 }
612
613 int UI_method_set_reader(UI_METHOD *method,
614                          int (*reader) (UI *ui, UI_STRING *uis))
615 {
616     if (method) {
617         method->ui_read_string = reader;
618         return 0;
619     } else
620         return -1;
621 }
622
623 int UI_method_set_closer(UI_METHOD *method, int (*closer) (UI *ui))
624 {
625     if (method) {
626         method->ui_close_session = closer;
627         return 0;
628     } else
629         return -1;
630 }
631
632 int UI_method_set_prompt_constructor(UI_METHOD *method,
633                                      char *(*prompt_constructor) (UI *ui,
634                                                                   const char
635                                                                   *object_desc,
636                                                                   const char
637                                                                   *object_name))
638 {
639     if (method) {
640         method->ui_construct_prompt = prompt_constructor;
641         return 0;
642     } else
643         return -1;
644 }
645
646 int (*UI_method_get_opener(UI_METHOD *method)) (UI *) {
647     if (method)
648         return method->ui_open_session;
649     else
650         return NULL;
651 }
652
653 int (*UI_method_get_writer(UI_METHOD *method)) (UI *, UI_STRING *) {
654     if (method)
655         return method->ui_write_string;
656     else
657         return NULL;
658 }
659
660 int (*UI_method_get_flusher(UI_METHOD *method)) (UI *) {
661     if (method)
662         return method->ui_flush;
663     else
664         return NULL;
665 }
666
667 int (*UI_method_get_reader(UI_METHOD *method)) (UI *, UI_STRING *) {
668     if (method)
669         return method->ui_read_string;
670     else
671         return NULL;
672 }
673
674 int (*UI_method_get_closer(UI_METHOD *method)) (UI *) {
675     if (method)
676         return method->ui_close_session;
677     else
678         return NULL;
679 }
680
681 char *(*UI_method_get_prompt_constructor(UI_METHOD *method)) (UI *,
682                                                               const char *,
683                                                               const char *) {
684     if (method)
685         return method->ui_construct_prompt;
686     else
687         return NULL;
688 }
689
690 enum UI_string_types UI_get_string_type(UI_STRING *uis)
691 {
692     return uis->type;
693 }
694
695 int UI_get_input_flags(UI_STRING *uis)
696 {
697     return uis->input_flags;
698 }
699
700 const char *UI_get0_output_string(UI_STRING *uis)
701 {
702     return uis->out_string;
703 }
704
705 const char *UI_get0_action_string(UI_STRING *uis)
706 {
707     switch (uis->type) {
708     case UIT_PROMPT:
709     case UIT_BOOLEAN:
710         return uis->_.boolean_data.action_desc;
711     case UIT_NONE:
712     case UIT_VERIFY:
713     case UIT_INFO:
714     case UIT_ERROR:
715         break;
716     }
717     return NULL;
718 }
719
720 const char *UI_get0_result_string(UI_STRING *uis)
721 {
722     switch (uis->type) {
723     case UIT_PROMPT:
724     case UIT_VERIFY:
725         return uis->result_buf;
726     case UIT_NONE:
727     case UIT_BOOLEAN:
728     case UIT_INFO:
729     case UIT_ERROR:
730         break;
731     }
732     return NULL;
733 }
734
735 const char *UI_get0_test_string(UI_STRING *uis)
736 {
737     switch (uis->type) {
738     case UIT_VERIFY:
739         return uis->_.string_data.test_buf;
740     case UIT_NONE:
741     case UIT_BOOLEAN:
742     case UIT_INFO:
743     case UIT_ERROR:
744     case UIT_PROMPT:
745         break;
746     }
747     return NULL;
748 }
749
750 int UI_get_result_minsize(UI_STRING *uis)
751 {
752     switch (uis->type) {
753     case UIT_PROMPT:
754     case UIT_VERIFY:
755         return uis->_.string_data.result_minsize;
756     case UIT_NONE:
757     case UIT_INFO:
758     case UIT_ERROR:
759     case UIT_BOOLEAN:
760         break;
761     }
762     return -1;
763 }
764
765 int UI_get_result_maxsize(UI_STRING *uis)
766 {
767     switch (uis->type) {
768     case UIT_PROMPT:
769     case UIT_VERIFY:
770         return uis->_.string_data.result_maxsize;
771     case UIT_NONE:
772     case UIT_INFO:
773     case UIT_ERROR:
774     case UIT_BOOLEAN:
775         break;
776     }
777     return -1;
778 }
779
780 int UI_set_result(UI *ui, UI_STRING *uis, const char *result)
781 {
782     int l = strlen(result);
783
784     ui->flags &= ~UI_FLAG_REDOABLE;
785
786     switch (uis->type) {
787     case UIT_PROMPT:
788     case UIT_VERIFY:
789         {
790             char number1[DECIMAL_SIZE(uis->_.string_data.result_minsize) + 1];
791             char number2[DECIMAL_SIZE(uis->_.string_data.result_maxsize) + 1];
792
793             BIO_snprintf(number1, sizeof(number1), "%d",
794                          uis->_.string_data.result_minsize);
795             BIO_snprintf(number2, sizeof(number2), "%d",
796                          uis->_.string_data.result_maxsize);
797
798             if (l < uis->_.string_data.result_minsize) {
799                 ui->flags |= UI_FLAG_REDOABLE;
800                 UIerr(UI_F_UI_SET_RESULT, UI_R_RESULT_TOO_SMALL);
801                 ERR_add_error_data(5, "You must type in ",
802                                    number1, " to ", number2, " characters");
803                 return -1;
804             }
805             if (l > uis->_.string_data.result_maxsize) {
806                 ui->flags |= UI_FLAG_REDOABLE;
807                 UIerr(UI_F_UI_SET_RESULT, UI_R_RESULT_TOO_LARGE);
808                 ERR_add_error_data(5, "You must type in ",
809                                    number1, " to ", number2, " characters");
810                 return -1;
811             }
812         }
813
814         if (uis->result_buf == NULL) {
815             UIerr(UI_F_UI_SET_RESULT, UI_R_NO_RESULT_BUFFER);
816             return -1;
817         }
818
819         OPENSSL_strlcpy(uis->result_buf, result,
820                     uis->_.string_data.result_maxsize + 1);
821         break;
822     case UIT_BOOLEAN:
823         {
824             const char *p;
825
826             if (uis->result_buf == NULL) {
827                 UIerr(UI_F_UI_SET_RESULT, UI_R_NO_RESULT_BUFFER);
828                 return -1;
829             }
830
831             uis->result_buf[0] = '\0';
832             for (p = result; *p; p++) {
833                 if (strchr(uis->_.boolean_data.ok_chars, *p)) {
834                     uis->result_buf[0] = uis->_.boolean_data.ok_chars[0];
835                     break;
836                 }
837                 if (strchr(uis->_.boolean_data.cancel_chars, *p)) {
838                     uis->result_buf[0] = uis->_.boolean_data.cancel_chars[0];
839                     break;
840                 }
841             }
842         }
843     case UIT_NONE:
844     case UIT_INFO:
845     case UIT_ERROR:
846         break;
847     }
848     return 0;
849 }