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