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