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