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