xref: /openbsd-src/lib/libcrypto/ui/ui_lib.c (revision e5157e49389faebcb42b7237d55fbf096d9c2523)
1 /* $OpenBSD: ui_lib.c,v 1.29 2014/10/03 06:02:38 doug 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 IMPLEMENT_STACK_OF(UI_STRING_ST) 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 				ok = -2;
495 				goto err;
496 			case 0:		/* Errors */
497 				ok = -1;
498 				goto err;
499 			default:	/* Success */
500 				ok = 0;
501 				break;
502 			}
503 		}
504 	}
505 
506 err:
507 	if (ui->meth->ui_close_session && !ui->meth->ui_close_session(ui))
508 		return -1;
509 	return ok;
510 }
511 
512 int
513 UI_ctrl(UI *ui, int cmd, long i, void *p, void (*f) (void))
514 {
515 	if (ui == NULL) {
516 		UIerr(UI_F_UI_CTRL, ERR_R_PASSED_NULL_PARAMETER);
517 		return -1;
518 	}
519 	switch (cmd) {
520 	case UI_CTRL_PRINT_ERRORS:
521 		{
522 			int save_flag = !!(ui->flags & UI_FLAG_PRINT_ERRORS);
523 			if (i)
524 				ui->flags |= UI_FLAG_PRINT_ERRORS;
525 			else
526 				ui->flags &= ~UI_FLAG_PRINT_ERRORS;
527 			return save_flag;
528 		}
529 	case UI_CTRL_IS_REDOABLE:
530 		return !!(ui->flags & UI_FLAG_REDOABLE);
531 	default:
532 		break;
533 	}
534 	UIerr(UI_F_UI_CTRL, UI_R_UNKNOWN_CONTROL_COMMAND);
535 	return -1;
536 }
537 
538 int
539 UI_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
540     CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func)
541 {
542 	return CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_UI, argl, argp,
543 	    new_func, dup_func, free_func);
544 }
545 
546 int
547 UI_set_ex_data(UI *r, int idx, void *arg)
548 {
549 	return (CRYPTO_set_ex_data(&r->ex_data, idx, arg));
550 }
551 
552 void *
553 UI_get_ex_data(UI *r, int idx)
554 {
555 	return (CRYPTO_get_ex_data(&r->ex_data, idx));
556 }
557 
558 void
559 UI_set_default_method(const UI_METHOD *meth)
560 {
561 	default_UI_meth = meth;
562 }
563 
564 const UI_METHOD *
565 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 *
574 UI_get_method(UI *ui)
575 {
576 	return ui->meth;
577 }
578 
579 const UI_METHOD *
580 UI_set_method(UI *ui, const UI_METHOD *meth)
581 {
582 	ui->meth = meth;
583 	return ui->meth;
584 }
585 
586 
587 UI_METHOD *
588 UI_create_method(char *name)
589 {
590 	UI_METHOD *ui_method = calloc(1, sizeof(UI_METHOD));
591 
592 	if (ui_method && name)
593 		ui_method->name = strdup(name);
594 
595 	return ui_method;
596 }
597 
598 /* BIG FSCKING WARNING!!!!  If you use this on a statically allocated method
599    (that is, it hasn't been allocated using UI_create_method(), you deserve
600    anything Murphy can throw at you and more!  You have been warned. */
601 void
602 UI_destroy_method(UI_METHOD *ui_method)
603 {
604 	free(ui_method->name);
605 	ui_method->name = NULL;
606 	free(ui_method);
607 }
608 
609 int
610 UI_method_set_opener(UI_METHOD *method, int (*opener)(UI *ui))
611 {
612 	if (method) {
613 		method->ui_open_session = opener;
614 		return 0;
615 	} else
616 		return -1;
617 }
618 
619 int
620 UI_method_set_writer(UI_METHOD *method, int (*writer)(UI *ui, UI_STRING *uis))
621 {
622 	if (method) {
623 		method->ui_write_string = writer;
624 		return 0;
625 	} else
626 		return -1;
627 }
628 
629 int
630 UI_method_set_flusher(UI_METHOD *method, int (*flusher)(UI *ui))
631 {
632 	if (method) {
633 		method->ui_flush = flusher;
634 		return 0;
635 	} else
636 		return -1;
637 }
638 
639 int
640 UI_method_set_reader(UI_METHOD *method, int (*reader)(UI *ui, UI_STRING *uis))
641 {
642 	if (method) {
643 		method->ui_read_string = reader;
644 		return 0;
645 	} else
646 		return -1;
647 }
648 
649 int
650 UI_method_set_closer(UI_METHOD *method, int (*closer)(UI *ui))
651 {
652 	if (method) {
653 		method->ui_close_session = closer;
654 		return 0;
655 	} else
656 		return -1;
657 }
658 
659 int
660 UI_method_set_prompt_constructor(UI_METHOD *method,
661     char *(*prompt_constructor)(UI *ui, const char *object_desc,
662     const char *object_name))
663 {
664 	if (method) {
665 		method->ui_construct_prompt = prompt_constructor;
666 		return 0;
667 	} else
668 		return -1;
669 }
670 
671 int
672 (*UI_method_get_opener(UI_METHOD * method))(UI *)
673 {
674 	if (method)
675 		return method->ui_open_session;
676 	else
677 		return NULL;
678 }
679 
680 int
681 (*UI_method_get_writer(UI_METHOD *method))(UI *, UI_STRING *)
682 {
683 	if (method)
684 		return method->ui_write_string;
685 	else
686 		return NULL;
687 }
688 
689 int
690 (*UI_method_get_flusher(UI_METHOD *method)) (UI *)
691 {
692 	if (method)
693 		return method->ui_flush;
694 	else
695 		return NULL;
696 }
697 
698 int
699 (*UI_method_get_reader(UI_METHOD *method))(UI *, UI_STRING *)
700 {
701 	if (method)
702 		return method->ui_read_string;
703 	else
704 		return NULL;
705 }
706 
707 int
708 (*UI_method_get_closer(UI_METHOD *method))(UI *)
709 {
710 	if (method)
711 		return method->ui_close_session;
712 	else
713 		return NULL;
714 }
715 
716 char *
717 (*UI_method_get_prompt_constructor(UI_METHOD *method))(UI *, const char *,
718     const char *)
719 {
720 	if (method)
721 		return method->ui_construct_prompt;
722 	else
723 		return NULL;
724 }
725 
726 enum UI_string_types
727 UI_get_string_type(UI_STRING *uis)
728 {
729 	if (!uis)
730 		return UIT_NONE;
731 	return uis->type;
732 }
733 
734 int
735 UI_get_input_flags(UI_STRING *uis)
736 {
737 	if (!uis)
738 		return 0;
739 	return uis->input_flags;
740 }
741 
742 const char *
743 UI_get0_output_string(UI_STRING *uis)
744 {
745 	if (!uis)
746 		return NULL;
747 	return uis->out_string;
748 }
749 
750 const char *
751 UI_get0_action_string(UI_STRING *uis)
752 {
753 	if (!uis)
754 		return NULL;
755 	switch (uis->type) {
756 	case UIT_PROMPT:
757 	case UIT_BOOLEAN:
758 		return uis->_.boolean_data.action_desc;
759 	default:
760 		return NULL;
761 	}
762 }
763 
764 const char *
765 UI_get0_result_string(UI_STRING *uis)
766 {
767 	if (!uis)
768 		return NULL;
769 	switch (uis->type) {
770 	case UIT_PROMPT:
771 	case UIT_VERIFY:
772 		return uis->result_buf;
773 	default:
774 		return NULL;
775 	}
776 }
777 
778 const char *
779 UI_get0_test_string(UI_STRING *uis)
780 {
781 	if (!uis)
782 		return NULL;
783 	switch (uis->type) {
784 	case UIT_VERIFY:
785 		return uis->_.string_data.test_buf;
786 	default:
787 		return NULL;
788 	}
789 }
790 
791 int
792 UI_get_result_minsize(UI_STRING *uis)
793 {
794 	if (!uis)
795 		return -1;
796 	switch (uis->type) {
797 	case UIT_PROMPT:
798 	case UIT_VERIFY:
799 		return uis->_.string_data.result_minsize;
800 	default:
801 		return -1;
802 	}
803 }
804 
805 int
806 UI_get_result_maxsize(UI_STRING *uis)
807 {
808 	if (!uis)
809 		return -1;
810 	switch (uis->type) {
811 	case UIT_PROMPT:
812 	case UIT_VERIFY:
813 		return uis->_.string_data.result_maxsize;
814 	default:
815 		return -1;
816 	}
817 }
818 
819 int
820 UI_set_result(UI *ui, UI_STRING *uis, const char *result)
821 {
822 	int l = strlen(result);
823 
824 	ui->flags &= ~UI_FLAG_REDOABLE;
825 
826 	if (!uis)
827 		return -1;
828 	switch (uis->type) {
829 	case UIT_PROMPT:
830 	case UIT_VERIFY:
831 		if (l < uis->_.string_data.result_minsize) {
832 			ui->flags |= UI_FLAG_REDOABLE;
833 			UIerr(UI_F_UI_SET_RESULT,
834 			    UI_R_RESULT_TOO_SMALL);
835 			ERR_asprintf_error_data
836 			    ("You must type in %d to %d characters",
837 				uis->_.string_data.result_minsize,
838 				uis->_.string_data.result_maxsize);
839 			return -1;
840 		}
841 		if (l > uis->_.string_data.result_maxsize) {
842 			ui->flags |= UI_FLAG_REDOABLE;
843 			UIerr(UI_F_UI_SET_RESULT,
844 			    UI_R_RESULT_TOO_LARGE);
845 			ERR_asprintf_error_data
846 			    ("You must type in %d to %d characters",
847 				uis->_.string_data.result_minsize,
848 				uis->_.string_data.result_maxsize);
849 			return -1;
850 		}
851 		if (!uis->result_buf) {
852 			UIerr(UI_F_UI_SET_RESULT, UI_R_NO_RESULT_BUFFER);
853 			return -1;
854 		}
855 		strlcpy(uis->result_buf, result,
856 		    uis->_.string_data.result_maxsize + 1);
857 		break;
858 	case UIT_BOOLEAN:
859 		{
860 			const char *p;
861 
862 			if (!uis->result_buf) {
863 				UIerr(UI_F_UI_SET_RESULT, UI_R_NO_RESULT_BUFFER);
864 				return -1;
865 			}
866 			uis->result_buf[0] = '\0';
867 			for (p = result; *p; p++) {
868 				if (strchr(uis->_.boolean_data.ok_chars, *p)) {
869 					uis->result_buf[0] =
870 					    uis->_.boolean_data.ok_chars[0];
871 					break;
872 				}
873 				if (strchr(uis->_.boolean_data.cancel_chars, *p)) {
874 					uis->result_buf[0] =
875 					    uis->_.boolean_data.cancel_chars[0];
876 					break;
877 				}
878 			}
879 		default:
880 			break;
881 		}
882 	}
883 	return 0;
884 }
885