xref: /dragonfly/crypto/libressl/crypto/ui/ui_lib.c (revision f5b1c8a1)
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 }
886