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