xref: /openbsd-src/lib/libcrypto/ui/ui_lib.c (revision 20175b857a0c3817cfda731930e8b4bca7ad6b00)
1da347917Sbeck /* crypto/ui/ui_lib.c -*- mode:C; c-file-style: "eay" -*- */
2da347917Sbeck /* Written by Richard Levitte (richard@levitte.org) for the OpenSSL
3da347917Sbeck  * project 2001.
4da347917Sbeck  */
5da347917Sbeck /* ====================================================================
6da347917Sbeck  * Copyright (c) 2001 The OpenSSL Project.  All rights reserved.
7da347917Sbeck  *
8da347917Sbeck  * Redistribution and use in source and binary forms, with or without
9da347917Sbeck  * modification, are permitted provided that the following conditions
10da347917Sbeck  * are met:
11da347917Sbeck  *
12da347917Sbeck  * 1. Redistributions of source code must retain the above copyright
13da347917Sbeck  *    notice, this list of conditions and the following disclaimer.
14da347917Sbeck  *
15da347917Sbeck  * 2. Redistributions in binary form must reproduce the above copyright
16da347917Sbeck  *    notice, this list of conditions and the following disclaimer in
17da347917Sbeck  *    the documentation and/or other materials provided with the
18da347917Sbeck  *    distribution.
19da347917Sbeck  *
20da347917Sbeck  * 3. All advertising materials mentioning features or use of this
21da347917Sbeck  *    software must display the following acknowledgment:
22da347917Sbeck  *    "This product includes software developed by the OpenSSL Project
23da347917Sbeck  *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
24da347917Sbeck  *
25da347917Sbeck  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
26da347917Sbeck  *    endorse or promote products derived from this software without
27da347917Sbeck  *    prior written permission. For written permission, please contact
28da347917Sbeck  *    openssl-core@openssl.org.
29da347917Sbeck  *
30da347917Sbeck  * 5. Products derived from this software may not be called "OpenSSL"
31da347917Sbeck  *    nor may "OpenSSL" appear in their names without prior written
32da347917Sbeck  *    permission of the OpenSSL Project.
33da347917Sbeck  *
34da347917Sbeck  * 6. Redistributions of any form whatsoever must retain the following
35da347917Sbeck  *    acknowledgment:
36da347917Sbeck  *    "This product includes software developed by the OpenSSL Project
37da347917Sbeck  *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
38da347917Sbeck  *
39da347917Sbeck  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40da347917Sbeck  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41da347917Sbeck  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42da347917Sbeck  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
43da347917Sbeck  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44da347917Sbeck  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45da347917Sbeck  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46da347917Sbeck  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47da347917Sbeck  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48da347917Sbeck  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49da347917Sbeck  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50da347917Sbeck  * OF THE POSSIBILITY OF SUCH DAMAGE.
51da347917Sbeck  * ====================================================================
52da347917Sbeck  *
53da347917Sbeck  * This product includes cryptographic software written by Eric Young
54da347917Sbeck  * (eay@cryptsoft.com).  This product includes software written by Tim
55da347917Sbeck  * Hudson (tjh@cryptsoft.com).
56da347917Sbeck  *
57da347917Sbeck  */
58da347917Sbeck 
59da347917Sbeck #include <string.h>
60*20175b85Sjsing 
61*20175b85Sjsing #include <openssl/opensslconf.h>
62*20175b85Sjsing 
634fcf65c5Sdjm #include "cryptlib.h"
64*20175b85Sjsing 
65da347917Sbeck #include <openssl/buffer.h>
66da347917Sbeck #include <openssl/ui.h>
67da347917Sbeck #include <openssl/err.h>
68da347917Sbeck #include "ui_locl.h"
69da347917Sbeck 
70c3bf3550Sjsing IMPLEMENT_STACK_OF(UI_STRING_ST) static const UI_METHOD *default_UI_meth = NULL;
71da347917Sbeck 
72c3bf3550Sjsing UI *
73c3bf3550Sjsing UI_new(void)
74da347917Sbeck {
75da347917Sbeck 	return (UI_new_method(NULL));
76da347917Sbeck }
77da347917Sbeck 
78764af611Stedu UI *
79764af611Stedu UI_new_method(const UI_METHOD *method)
80da347917Sbeck {
81da347917Sbeck 	UI *ret;
82da347917Sbeck 
836f3a6cb1Sbeck 	ret = (UI *) malloc(sizeof(UI));
84764af611Stedu 	if (ret == NULL) {
85da347917Sbeck 		UIerr(UI_F_UI_NEW_METHOD, ERR_R_MALLOC_FAILURE);
86da347917Sbeck 		return NULL;
87da347917Sbeck 	}
88da347917Sbeck 	if (method == NULL)
89da347917Sbeck 		ret->meth = UI_get_default_method();
90da347917Sbeck 	else
91da347917Sbeck 		ret->meth = method;
92da347917Sbeck 
93da347917Sbeck 	ret->strings = NULL;
94da347917Sbeck 	ret->user_data = NULL;
9550c17820Sdjm 	ret->flags = 0;
96da347917Sbeck 	CRYPTO_new_ex_data(CRYPTO_EX_INDEX_UI, ret, &ret->ex_data);
97da347917Sbeck 	return ret;
98da347917Sbeck }
99da347917Sbeck 
100764af611Stedu static void
101764af611Stedu free_string(UI_STRING *uis)
102da347917Sbeck {
103764af611Stedu 	if (uis->flags & OUT_STRING_FREEABLE) {
1046f3a6cb1Sbeck 		free((char *) uis->out_string);
105764af611Stedu 		switch (uis->type) {
106da347917Sbeck 		case UIT_BOOLEAN:
1076f3a6cb1Sbeck 			free((char *)uis->_.boolean_data.action_desc);
1086f3a6cb1Sbeck 			free((char *)uis->_.boolean_data.ok_chars);
1096f3a6cb1Sbeck 			free((char *)uis->_.boolean_data.cancel_chars);
110da347917Sbeck 			break;
111da347917Sbeck 		default:
112da347917Sbeck 			break;
113da347917Sbeck 		}
114da347917Sbeck 	}
1156f3a6cb1Sbeck 	free(uis);
116da347917Sbeck }
117da347917Sbeck 
118764af611Stedu void
119764af611Stedu UI_free(UI *ui)
120da347917Sbeck {
121da347917Sbeck 	if (ui == NULL)
122da347917Sbeck 		return;
123da347917Sbeck 	sk_UI_STRING_pop_free(ui->strings, free_string);
124da347917Sbeck 	CRYPTO_free_ex_data(CRYPTO_EX_INDEX_UI, ui, &ui->ex_data);
1256f3a6cb1Sbeck 	free(ui);
126da347917Sbeck }
127da347917Sbeck 
128764af611Stedu static int
129764af611Stedu allocate_string_stack(UI *ui)
130da347917Sbeck {
131764af611Stedu 	if (ui->strings == NULL) {
132da347917Sbeck 		ui->strings = sk_UI_STRING_new_null();
133764af611Stedu 		if (ui->strings == NULL) {
134da347917Sbeck 			return -1;
135da347917Sbeck 		}
136da347917Sbeck 	}
137da347917Sbeck 	return 0;
138da347917Sbeck }
139da347917Sbeck 
140764af611Stedu static UI_STRING *
141ba586daeSjsing general_allocate_prompt(UI *ui, const char *prompt, int prompt_freeable,
142ba586daeSjsing     enum UI_string_types type, int input_flags, char *result_buf)
143da347917Sbeck {
144da347917Sbeck 	UI_STRING *ret = NULL;
145da347917Sbeck 
146764af611Stedu 	if (prompt == NULL) {
147ba586daeSjsing 		UIerr(UI_F_GENERAL_ALLOCATE_PROMPT,
148ba586daeSjsing 		    ERR_R_PASSED_NULL_PARAMETER);
149c3bf3550Sjsing 	} else if ((type == UIT_PROMPT || type == UIT_VERIFY ||
150c3bf3550Sjsing 	    type == UIT_BOOLEAN) && result_buf == NULL) {
151da347917Sbeck 		UIerr(UI_F_GENERAL_ALLOCATE_PROMPT, UI_R_NO_RESULT_BUFFER);
152764af611Stedu 	} else if ((ret = (UI_STRING *) malloc(sizeof(UI_STRING)))) {
153da347917Sbeck 		ret->out_string = prompt;
154da347917Sbeck 		ret->flags = prompt_freeable ? OUT_STRING_FREEABLE : 0;
155da347917Sbeck 		ret->input_flags = input_flags;
156da347917Sbeck 		ret->type = type;
157da347917Sbeck 		ret->result_buf = result_buf;
158da347917Sbeck 	}
159da347917Sbeck 	return ret;
160da347917Sbeck }
161da347917Sbeck 
162764af611Stedu static int
163ba586daeSjsing general_allocate_string(UI *ui, const char *prompt, int prompt_freeable,
164ba586daeSjsing     enum UI_string_types type, int input_flags, char *result_buf, int minsize,
165ba586daeSjsing     int maxsize, const char *test_buf)
166da347917Sbeck {
167da347917Sbeck 	int ret = -1;
168da347917Sbeck 	UI_STRING *s = general_allocate_prompt(ui, prompt, prompt_freeable,
169da347917Sbeck 	    type, input_flags, result_buf);
170da347917Sbeck 
171764af611Stedu 	if (s) {
172764af611Stedu 		if (allocate_string_stack(ui) >= 0) {
173da347917Sbeck 			s->_.string_data.result_minsize = minsize;
174da347917Sbeck 			s->_.string_data.result_maxsize = maxsize;
175da347917Sbeck 			s->_.string_data.test_buf = test_buf;
176da347917Sbeck 			ret = sk_UI_STRING_push(ui->strings, s);
177da347917Sbeck 			/* sk_push() returns 0 on error.  Let's addapt that */
178764af611Stedu 			if (ret <= 0)
179764af611Stedu 				ret--;
180764af611Stedu 		} else
181da347917Sbeck 			free_string(s);
182da347917Sbeck 	}
183da347917Sbeck 	return ret;
184da347917Sbeck }
185da347917Sbeck 
186764af611Stedu static int
187ba586daeSjsing general_allocate_boolean(UI *ui, const char *prompt, const char *action_desc,
188ba586daeSjsing     const char *ok_chars, const char *cancel_chars, int prompt_freeable,
189ba586daeSjsing     enum UI_string_types type, int input_flags, char *result_buf)
190da347917Sbeck {
191da347917Sbeck 	int ret = -1;
192da347917Sbeck 	UI_STRING *s;
193da347917Sbeck 	const char *p;
194da347917Sbeck 
195764af611Stedu 	if (ok_chars == NULL) {
196ba586daeSjsing 		UIerr(UI_F_GENERAL_ALLOCATE_BOOLEAN,
197ba586daeSjsing 		    ERR_R_PASSED_NULL_PARAMETER);
198764af611Stedu 	} else if (cancel_chars == NULL) {
199ba586daeSjsing 		UIerr(UI_F_GENERAL_ALLOCATE_BOOLEAN,
200ba586daeSjsing 		    ERR_R_PASSED_NULL_PARAMETER);
201764af611Stedu 	} else {
202764af611Stedu 		for (p = ok_chars; *p; p++) {
203764af611Stedu 			if (strchr(cancel_chars, *p)) {
204da347917Sbeck 				UIerr(UI_F_GENERAL_ALLOCATE_BOOLEAN,
205da347917Sbeck 				    UI_R_COMMON_OK_AND_CANCEL_CHARACTERS);
206da347917Sbeck 			}
207da347917Sbeck 		}
208da347917Sbeck 
209da347917Sbeck 		s = general_allocate_prompt(ui, prompt, prompt_freeable,
210da347917Sbeck 		    type, input_flags, result_buf);
211da347917Sbeck 
212764af611Stedu 		if (s) {
213764af611Stedu 			if (allocate_string_stack(ui) >= 0) {
214da347917Sbeck 				s->_.boolean_data.action_desc = action_desc;
215da347917Sbeck 				s->_.boolean_data.ok_chars = ok_chars;
216da347917Sbeck 				s->_.boolean_data.cancel_chars = cancel_chars;
217da347917Sbeck 				ret = sk_UI_STRING_push(ui->strings, s);
218764af611Stedu 				/*
219764af611Stedu 				 * sk_push() returns 0 on error. Let's addapt
220764af611Stedu 				 * that
221764af611Stedu 				 */
222764af611Stedu 				if (ret <= 0)
223764af611Stedu 					ret--;
224764af611Stedu 			} else
225da347917Sbeck 				free_string(s);
226da347917Sbeck 		}
227da347917Sbeck 	}
228da347917Sbeck 	return ret;
229da347917Sbeck }
230da347917Sbeck 
231767fe2ffSmarkus /* Returns the index to the place in the stack or -1 for error.  Uses a
232da347917Sbeck    direct reference to the prompt.  */
233764af611Stedu int
234ba586daeSjsing UI_add_input_string(UI *ui, const char *prompt, int flags, char *result_buf,
235ba586daeSjsing     int minsize, int maxsize)
236da347917Sbeck {
237ba586daeSjsing 	return general_allocate_string(ui, prompt, 0, UIT_PROMPT, flags,
238ba586daeSjsing 	    result_buf, minsize, maxsize, NULL);
239da347917Sbeck }
240da347917Sbeck 
241da347917Sbeck /* Same as UI_add_input_string(), excepts it takes a copy of the prompt */
242764af611Stedu int
243ba586daeSjsing UI_dup_input_string(UI *ui, const char *prompt, int flags, char *result_buf,
244ba586daeSjsing     int minsize, int maxsize)
245da347917Sbeck {
246da347917Sbeck 	char *prompt_copy = NULL;
247da347917Sbeck 
248764af611Stedu 	if (prompt) {
249da347917Sbeck 		prompt_copy = BUF_strdup(prompt);
250764af611Stedu 		if (prompt_copy == NULL) {
251da347917Sbeck 			UIerr(UI_F_UI_DUP_INPUT_STRING, ERR_R_MALLOC_FAILURE);
252da347917Sbeck 			return 0;
253da347917Sbeck 		}
254da347917Sbeck 	}
255ba586daeSjsing 	return general_allocate_string(ui, prompt_copy, 1, UIT_PROMPT, flags,
256ba586daeSjsing 	    result_buf, minsize, maxsize, NULL);
257da347917Sbeck }
258da347917Sbeck 
259764af611Stedu int
260ba586daeSjsing UI_add_verify_string(UI *ui, const char *prompt, int flags, char *result_buf,
261ba586daeSjsing     int minsize, int maxsize, const char *test_buf)
262da347917Sbeck {
263ba586daeSjsing 	return general_allocate_string(ui, prompt, 0, UIT_VERIFY, flags,
264ba586daeSjsing 	    result_buf, minsize, maxsize, test_buf);
265da347917Sbeck }
266da347917Sbeck 
267764af611Stedu int
268764af611Stedu UI_dup_verify_string(UI *ui, const char *prompt, int flags,
269da347917Sbeck     char *result_buf, int minsize, int maxsize, const char *test_buf)
270da347917Sbeck {
271da347917Sbeck 	char *prompt_copy = NULL;
272da347917Sbeck 
273764af611Stedu 	if (prompt) {
274da347917Sbeck 		prompt_copy = BUF_strdup(prompt);
275764af611Stedu 		if (prompt_copy == NULL) {
276da347917Sbeck 			UIerr(UI_F_UI_DUP_VERIFY_STRING, ERR_R_MALLOC_FAILURE);
277da347917Sbeck 			return -1;
278da347917Sbeck 		}
279da347917Sbeck 	}
280ba586daeSjsing 	return general_allocate_string(ui, prompt_copy, 1, UIT_VERIFY, flags,
281ba586daeSjsing 	    result_buf, minsize, maxsize, test_buf);
282da347917Sbeck }
283da347917Sbeck 
284764af611Stedu int
285764af611Stedu UI_add_input_boolean(UI *ui, const char *prompt, const char *action_desc,
286ba586daeSjsing     const char *ok_chars, const char *cancel_chars, int flags, char *result_buf)
287da347917Sbeck {
288ba586daeSjsing 	return general_allocate_boolean(ui, prompt, action_desc, ok_chars,
289ba586daeSjsing 	    cancel_chars, 0, UIT_BOOLEAN, flags, result_buf);
290da347917Sbeck }
291da347917Sbeck 
292764af611Stedu int
293764af611Stedu UI_dup_input_boolean(UI *ui, const char *prompt, const char *action_desc,
294ba586daeSjsing     const char *ok_chars, const char *cancel_chars, int flags, char *result_buf)
295da347917Sbeck {
296da347917Sbeck 	char *prompt_copy = NULL;
297da347917Sbeck 	char *action_desc_copy = NULL;
298da347917Sbeck 	char *ok_chars_copy = NULL;
299da347917Sbeck 	char *cancel_chars_copy = NULL;
300da347917Sbeck 
301764af611Stedu 	if (prompt) {
302da347917Sbeck 		prompt_copy = BUF_strdup(prompt);
303764af611Stedu 		if (prompt_copy == NULL) {
304da347917Sbeck 			UIerr(UI_F_UI_DUP_INPUT_BOOLEAN, ERR_R_MALLOC_FAILURE);
305da347917Sbeck 			goto err;
306da347917Sbeck 		}
307da347917Sbeck 	}
308764af611Stedu 	if (action_desc) {
309da347917Sbeck 		action_desc_copy = BUF_strdup(action_desc);
310764af611Stedu 		if (action_desc_copy == NULL) {
311da347917Sbeck 			UIerr(UI_F_UI_DUP_INPUT_BOOLEAN, ERR_R_MALLOC_FAILURE);
312da347917Sbeck 			goto err;
313da347917Sbeck 		}
314da347917Sbeck 	}
315764af611Stedu 	if (ok_chars) {
316da347917Sbeck 		ok_chars_copy = BUF_strdup(ok_chars);
317764af611Stedu 		if (ok_chars_copy == NULL) {
318da347917Sbeck 			UIerr(UI_F_UI_DUP_INPUT_BOOLEAN, ERR_R_MALLOC_FAILURE);
319da347917Sbeck 			goto err;
320da347917Sbeck 		}
321da347917Sbeck 	}
322764af611Stedu 	if (cancel_chars) {
323da347917Sbeck 		cancel_chars_copy = BUF_strdup(cancel_chars);
324764af611Stedu 		if (cancel_chars_copy == NULL) {
325da347917Sbeck 			UIerr(UI_F_UI_DUP_INPUT_BOOLEAN, ERR_R_MALLOC_FAILURE);
326da347917Sbeck 			goto err;
327da347917Sbeck 		}
328da347917Sbeck 	}
329da347917Sbeck 	return general_allocate_boolean(ui, prompt_copy, action_desc_copy,
330da347917Sbeck 	    ok_chars_copy, cancel_chars_copy, 1, UIT_BOOLEAN, flags,
331da347917Sbeck 	    result_buf);
332c3bf3550Sjsing 
333da347917Sbeck err:
334764af611Stedu 	free(prompt_copy);
335764af611Stedu 	free(action_desc_copy);
336764af611Stedu 	free(ok_chars_copy);
337764af611Stedu 	free(cancel_chars_copy);
338da347917Sbeck 	return -1;
339da347917Sbeck }
340da347917Sbeck 
341764af611Stedu int
342764af611Stedu UI_add_info_string(UI *ui, const char *text)
343da347917Sbeck {
344da347917Sbeck 	return general_allocate_string(ui, text, 0, UIT_INFO, 0, NULL, 0, 0,
345da347917Sbeck 	    NULL);
346da347917Sbeck }
347da347917Sbeck 
348764af611Stedu int
349764af611Stedu UI_dup_info_string(UI *ui, const char *text)
350da347917Sbeck {
351da347917Sbeck 	char *text_copy = NULL;
352da347917Sbeck 
353764af611Stedu 	if (text) {
354da347917Sbeck 		text_copy = BUF_strdup(text);
355764af611Stedu 		if (text_copy == NULL) {
356da347917Sbeck 			UIerr(UI_F_UI_DUP_INFO_STRING, ERR_R_MALLOC_FAILURE);
357da347917Sbeck 			return -1;
358da347917Sbeck 		}
359da347917Sbeck 	}
360da347917Sbeck 	return general_allocate_string(ui, text_copy, 1, UIT_INFO, 0, NULL,
361da347917Sbeck 	    0, 0, NULL);
362da347917Sbeck }
363da347917Sbeck 
364764af611Stedu int
365764af611Stedu UI_add_error_string(UI *ui, const char *text)
366da347917Sbeck {
367da347917Sbeck 	return general_allocate_string(ui, text, 0, UIT_ERROR, 0, NULL, 0, 0,
368da347917Sbeck 	    NULL);
369da347917Sbeck }
370da347917Sbeck 
371764af611Stedu int
372764af611Stedu UI_dup_error_string(UI *ui, const char *text)
373da347917Sbeck {
374da347917Sbeck 	char *text_copy = NULL;
375da347917Sbeck 
376764af611Stedu 	if (text) {
377da347917Sbeck 		text_copy = BUF_strdup(text);
378764af611Stedu 		if (text_copy == NULL) {
379da347917Sbeck 			UIerr(UI_F_UI_DUP_ERROR_STRING, ERR_R_MALLOC_FAILURE);
380da347917Sbeck 			return -1;
381da347917Sbeck 		}
382da347917Sbeck 	}
383da347917Sbeck 	return general_allocate_string(ui, text_copy, 1, UIT_ERROR, 0, NULL,
384da347917Sbeck 	    0, 0, NULL);
385da347917Sbeck }
386da347917Sbeck 
387764af611Stedu char *
388c3bf3550Sjsing UI_construct_prompt(UI *ui, const char *object_desc, const char *object_name)
389da347917Sbeck {
390005a942cSjsing 	const char *format = "Enter %s for %s:";
39164a2fea0Sjsing 	char *prompt;
392da347917Sbeck 
393da347917Sbeck 	if (ui->meth->ui_construct_prompt)
39464a2fea0Sjsing 		return ui->meth->ui_construct_prompt(ui, object_desc,
39564a2fea0Sjsing 		    object_name);
396da347917Sbeck 
397da347917Sbeck 	if (object_desc == NULL)
398da347917Sbeck 		return NULL;
39964a2fea0Sjsing 	if (object_name == NULL)
40064a2fea0Sjsing 		format = "Enter %s:";
40164a2fea0Sjsing 	if (asprintf(&prompt, format, object_desc, object_name) == -1)
40264a2fea0Sjsing 		return NULL;
403da347917Sbeck 
404da347917Sbeck 	return prompt;
405da347917Sbeck }
406da347917Sbeck 
407764af611Stedu void *
408764af611Stedu UI_add_user_data(UI *ui, void *user_data)
409da347917Sbeck {
410da347917Sbeck 	void *old_data = ui->user_data;
411ba586daeSjsing 
412da347917Sbeck 	ui->user_data = user_data;
413da347917Sbeck 	return old_data;
414da347917Sbeck }
415da347917Sbeck 
416764af611Stedu void *
417764af611Stedu UI_get0_user_data(UI *ui)
418da347917Sbeck {
419da347917Sbeck 	return ui->user_data;
420da347917Sbeck }
421da347917Sbeck 
422764af611Stedu const char *
423764af611Stedu UI_get0_result(UI *ui, int i)
424da347917Sbeck {
425764af611Stedu 	if (i < 0) {
426da347917Sbeck 		UIerr(UI_F_UI_GET0_RESULT, UI_R_INDEX_TOO_SMALL);
427da347917Sbeck 		return NULL;
428da347917Sbeck 	}
429764af611Stedu 	if (i >= sk_UI_STRING_num(ui->strings)) {
430da347917Sbeck 		UIerr(UI_F_UI_GET0_RESULT, UI_R_INDEX_TOO_LARGE);
431da347917Sbeck 		return NULL;
432da347917Sbeck 	}
433da347917Sbeck 	return UI_get0_result_string(sk_UI_STRING_value(ui->strings, i));
434da347917Sbeck }
435da347917Sbeck 
436764af611Stedu static int
437764af611Stedu print_error(const char *str, size_t len, UI *ui)
438da347917Sbeck {
439da347917Sbeck 	UI_STRING uis;
440da347917Sbeck 
441da347917Sbeck 	memset(&uis, 0, sizeof(uis));
442da347917Sbeck 	uis.type = UIT_ERROR;
443da347917Sbeck 	uis.out_string = str;
444da347917Sbeck 
445c3bf3550Sjsing 	if (ui->meth->ui_write_string &&
446c3bf3550Sjsing 	    !ui->meth->ui_write_string(ui, &uis))
447da347917Sbeck 		return -1;
448da347917Sbeck 	return 0;
449da347917Sbeck }
450da347917Sbeck 
451764af611Stedu int
452764af611Stedu UI_process(UI *ui)
453da347917Sbeck {
454da347917Sbeck 	int i, ok = 0;
455da347917Sbeck 
456da347917Sbeck 	if (ui->meth->ui_open_session && !ui->meth->ui_open_session(ui))
457da347917Sbeck 		return -1;
458da347917Sbeck 
459da347917Sbeck 	if (ui->flags & UI_FLAG_PRINT_ERRORS)
460da347917Sbeck 		ERR_print_errors_cb(
461da347917Sbeck 		    (int (*)(const char *, size_t, void *)) print_error,
462da347917Sbeck 		    (void *)ui);
463da347917Sbeck 
464764af611Stedu 	for (i = 0; i < sk_UI_STRING_num(ui->strings); i++) {
465c3bf3550Sjsing 		if (ui->meth->ui_write_string &&
466c3bf3550Sjsing 		    !ui->meth->ui_write_string(ui,
467764af611Stedu 			sk_UI_STRING_value(ui->strings, i))) {
468da347917Sbeck 			ok = -1;
469da347917Sbeck 			goto err;
470da347917Sbeck 		}
471da347917Sbeck 	}
472da347917Sbeck 
473da347917Sbeck 	if (ui->meth->ui_flush)
474764af611Stedu 		switch (ui->meth->ui_flush(ui)) {
475da347917Sbeck 		case -1:	/* Interrupt/Cancel/something... */
476da347917Sbeck 			ok = -2;
477da347917Sbeck 			goto err;
478da347917Sbeck 		case 0:		/* Errors */
479da347917Sbeck 			ok = -1;
480da347917Sbeck 			goto err;
481da347917Sbeck 		default:	/* Success */
482da347917Sbeck 			ok = 0;
483da347917Sbeck 			break;
484da347917Sbeck 		}
485da347917Sbeck 
486764af611Stedu 	for (i = 0; i < sk_UI_STRING_num(ui->strings); i++) {
487764af611Stedu 		if (ui->meth->ui_read_string) {
488da347917Sbeck 			switch (ui->meth->ui_read_string(ui,
489764af611Stedu 			    sk_UI_STRING_value(ui->strings, i))) {
490da347917Sbeck 			case -1:	/* Interrupt/Cancel/something... */
491da347917Sbeck 				ok = -2;
492da347917Sbeck 				goto err;
493da347917Sbeck 			case 0:		/* Errors */
494da347917Sbeck 				ok = -1;
495da347917Sbeck 				goto err;
496da347917Sbeck 			default:	/* Success */
497da347917Sbeck 				ok = 0;
498da347917Sbeck 				break;
499da347917Sbeck 			}
500da347917Sbeck 		}
501da347917Sbeck 	}
502ba586daeSjsing 
503da347917Sbeck err:
504da347917Sbeck 	if (ui->meth->ui_close_session && !ui->meth->ui_close_session(ui))
505da347917Sbeck 		return -1;
506da347917Sbeck 	return ok;
507da347917Sbeck }
508da347917Sbeck 
509764af611Stedu int
510764af611Stedu UI_ctrl(UI *ui, int cmd, long i, void *p, void (*f) (void))
511da347917Sbeck {
512764af611Stedu 	if (ui == NULL) {
513da347917Sbeck 		UIerr(UI_F_UI_CTRL, ERR_R_PASSED_NULL_PARAMETER);
514da347917Sbeck 		return -1;
515da347917Sbeck 	}
516764af611Stedu 	switch (cmd) {
517da347917Sbeck 	case UI_CTRL_PRINT_ERRORS:
518da347917Sbeck 		{
519da347917Sbeck 			int save_flag = !!(ui->flags & UI_FLAG_PRINT_ERRORS);
520da347917Sbeck 			if (i)
521da347917Sbeck 				ui->flags |= UI_FLAG_PRINT_ERRORS;
522da347917Sbeck 			else
523da347917Sbeck 				ui->flags &= ~UI_FLAG_PRINT_ERRORS;
524da347917Sbeck 			return save_flag;
525da347917Sbeck 		}
526da347917Sbeck 	case UI_CTRL_IS_REDOABLE:
527da347917Sbeck 		return !!(ui->flags & UI_FLAG_REDOABLE);
528da347917Sbeck 	default:
529da347917Sbeck 		break;
530da347917Sbeck 	}
531da347917Sbeck 	UIerr(UI_F_UI_CTRL, UI_R_UNKNOWN_CONTROL_COMMAND);
532da347917Sbeck 	return -1;
533da347917Sbeck }
534da347917Sbeck 
535764af611Stedu int
536764af611Stedu UI_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
537da347917Sbeck     CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func)
538da347917Sbeck {
539da347917Sbeck 	return CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_UI, argl, argp,
540da347917Sbeck 	    new_func, dup_func, free_func);
541da347917Sbeck }
542da347917Sbeck 
543764af611Stedu int
544764af611Stedu UI_set_ex_data(UI *r, int idx, void *arg)
545da347917Sbeck {
546da347917Sbeck 	return (CRYPTO_set_ex_data(&r->ex_data, idx, arg));
547da347917Sbeck }
548da347917Sbeck 
549764af611Stedu void *
550764af611Stedu UI_get_ex_data(UI *r, int idx)
551da347917Sbeck {
552da347917Sbeck 	return (CRYPTO_get_ex_data(&r->ex_data, idx));
553da347917Sbeck }
554da347917Sbeck 
555764af611Stedu void
556764af611Stedu UI_set_default_method(const UI_METHOD *meth)
557da347917Sbeck {
558da347917Sbeck 	default_UI_meth = meth;
559da347917Sbeck }
560da347917Sbeck 
561764af611Stedu const UI_METHOD *
562764af611Stedu UI_get_default_method(void)
563da347917Sbeck {
564764af611Stedu 	if (default_UI_meth == NULL) {
565da347917Sbeck 		default_UI_meth = UI_OpenSSL();
566da347917Sbeck 	}
567da347917Sbeck 	return default_UI_meth;
568da347917Sbeck }
569da347917Sbeck 
570764af611Stedu const UI_METHOD *
571764af611Stedu UI_get_method(UI *ui)
572da347917Sbeck {
573da347917Sbeck 	return ui->meth;
574da347917Sbeck }
575da347917Sbeck 
576764af611Stedu const UI_METHOD *
577764af611Stedu UI_set_method(UI *ui, const UI_METHOD *meth)
578da347917Sbeck {
579da347917Sbeck 	ui->meth = meth;
580da347917Sbeck 	return ui->meth;
581da347917Sbeck }
582da347917Sbeck 
583da347917Sbeck 
584764af611Stedu UI_METHOD *
585764af611Stedu UI_create_method(char *name)
586da347917Sbeck {
5876f3a6cb1Sbeck 	UI_METHOD *ui_method = (UI_METHOD *)malloc(sizeof(UI_METHOD));
588da347917Sbeck 
589764af611Stedu 	if (ui_method) {
590da347917Sbeck 		memset(ui_method, 0, sizeof(*ui_method));
591da347917Sbeck 		ui_method->name = BUF_strdup(name);
5924fcf65c5Sdjm 	}
593da347917Sbeck 	return ui_method;
594da347917Sbeck }
595da347917Sbeck 
596da347917Sbeck /* BIG FSCKING WARNING!!!!  If you use this on a statically allocated method
597da347917Sbeck    (that is, it hasn't been allocated using UI_create_method(), you deserve
598da347917Sbeck    anything Murphy can throw at you and more!  You have been warned. */
599764af611Stedu void
600764af611Stedu UI_destroy_method(UI_METHOD *ui_method)
601da347917Sbeck {
6026f3a6cb1Sbeck 	free(ui_method->name);
603da347917Sbeck 	ui_method->name = NULL;
6046f3a6cb1Sbeck 	free(ui_method);
605da347917Sbeck }
606da347917Sbeck 
607764af611Stedu int
608764af611Stedu UI_method_set_opener(UI_METHOD *method, int (*opener)(UI *ui))
609da347917Sbeck {
610764af611Stedu 	if (method) {
611da347917Sbeck 		method->ui_open_session = opener;
612da347917Sbeck 		return 0;
613764af611Stedu 	} else
614da347917Sbeck 		return -1;
615da347917Sbeck }
616da347917Sbeck 
617764af611Stedu int
618764af611Stedu UI_method_set_writer(UI_METHOD *method, int (*writer)(UI *ui, UI_STRING *uis))
619da347917Sbeck {
620764af611Stedu 	if (method) {
621da347917Sbeck 		method->ui_write_string = writer;
622da347917Sbeck 		return 0;
623764af611Stedu 	} else
624da347917Sbeck 		return -1;
625da347917Sbeck }
626da347917Sbeck 
627764af611Stedu int
628764af611Stedu UI_method_set_flusher(UI_METHOD *method, int (*flusher)(UI *ui))
629da347917Sbeck {
630764af611Stedu 	if (method) {
631da347917Sbeck 		method->ui_flush = flusher;
632da347917Sbeck 		return 0;
633764af611Stedu 	} else
634da347917Sbeck 		return -1;
635da347917Sbeck }
636da347917Sbeck 
637764af611Stedu int
638764af611Stedu UI_method_set_reader(UI_METHOD *method, int (*reader)(UI *ui, UI_STRING *uis))
639da347917Sbeck {
640764af611Stedu 	if (method) {
641da347917Sbeck 		method->ui_read_string = reader;
642da347917Sbeck 		return 0;
643764af611Stedu 	} else
644da347917Sbeck 		return -1;
645da347917Sbeck }
646da347917Sbeck 
647764af611Stedu int
648764af611Stedu UI_method_set_closer(UI_METHOD *method, int (*closer)(UI *ui))
649da347917Sbeck {
650764af611Stedu 	if (method) {
651da347917Sbeck 		method->ui_close_session = closer;
652da347917Sbeck 		return 0;
653764af611Stedu 	} else
654da347917Sbeck 		return -1;
655da347917Sbeck }
656da347917Sbeck 
657764af611Stedu int
658c3bf3550Sjsing UI_method_set_prompt_constructor(UI_METHOD *method,
659c3bf3550Sjsing     char *(*prompt_constructor)(UI *ui, const char *object_desc,
660c3bf3550Sjsing     const char *object_name))
6610a5d6edeSdjm {
662764af611Stedu 	if (method) {
6630a5d6edeSdjm 		method->ui_construct_prompt = prompt_constructor;
6640a5d6edeSdjm 		return 0;
665764af611Stedu 	} else
6660a5d6edeSdjm 		return -1;
6670a5d6edeSdjm }
6680a5d6edeSdjm 
669c3bf3550Sjsing int
670c3bf3550Sjsing (*UI_method_get_opener(UI_METHOD * method))(UI *)
671da347917Sbeck {
672da347917Sbeck 	if (method)
673da347917Sbeck 		return method->ui_open_session;
674da347917Sbeck 	else
675da347917Sbeck 		return NULL;
676da347917Sbeck }
677da347917Sbeck 
678c3bf3550Sjsing int
679c3bf3550Sjsing (*UI_method_get_writer(UI_METHOD *method))(UI *, UI_STRING *)
680da347917Sbeck {
681da347917Sbeck 	if (method)
682da347917Sbeck 		return method->ui_write_string;
683da347917Sbeck 	else
684da347917Sbeck 		return NULL;
685da347917Sbeck }
686da347917Sbeck 
687c3bf3550Sjsing int
688c3bf3550Sjsing (*UI_method_get_flusher(UI_METHOD *method)) (UI *)
689da347917Sbeck {
690da347917Sbeck 	if (method)
691da347917Sbeck 		return method->ui_flush;
692da347917Sbeck 	else
693da347917Sbeck 		return NULL;
694da347917Sbeck }
695da347917Sbeck 
696c3bf3550Sjsing int
697c3bf3550Sjsing (*UI_method_get_reader(UI_METHOD *method))(UI *, UI_STRING *)
698da347917Sbeck {
699da347917Sbeck 	if (method)
700da347917Sbeck 		return method->ui_read_string;
701da347917Sbeck 	else
702da347917Sbeck 		return NULL;
703da347917Sbeck }
704da347917Sbeck 
705c3bf3550Sjsing int
706c3bf3550Sjsing (*UI_method_get_closer(UI_METHOD *method))(UI *)
707da347917Sbeck {
708da347917Sbeck 	if (method)
709da347917Sbeck 		return method->ui_close_session;
710da347917Sbeck 	else
711da347917Sbeck 		return NULL;
712da347917Sbeck }
713da347917Sbeck 
714c3bf3550Sjsing char *
715c3bf3550Sjsing (*UI_method_get_prompt_constructor(UI_METHOD *method))(UI *, const char *,
716c3bf3550Sjsing     const char *)
7170a5d6edeSdjm {
7180a5d6edeSdjm 	if (method)
7190a5d6edeSdjm 		return method->ui_construct_prompt;
7200a5d6edeSdjm 	else
7210a5d6edeSdjm 		return NULL;
7220a5d6edeSdjm }
7230a5d6edeSdjm 
724764af611Stedu enum UI_string_types
725764af611Stedu UI_get_string_type(UI_STRING *uis)
726da347917Sbeck {
727da347917Sbeck 	if (!uis)
728da347917Sbeck 		return UIT_NONE;
729da347917Sbeck 	return uis->type;
730da347917Sbeck }
731da347917Sbeck 
732764af611Stedu int
733764af611Stedu UI_get_input_flags(UI_STRING *uis)
734da347917Sbeck {
735da347917Sbeck 	if (!uis)
736da347917Sbeck 		return 0;
737da347917Sbeck 	return uis->input_flags;
738da347917Sbeck }
739da347917Sbeck 
740764af611Stedu const char *
741764af611Stedu UI_get0_output_string(UI_STRING *uis)
742da347917Sbeck {
743da347917Sbeck 	if (!uis)
744da347917Sbeck 		return NULL;
745da347917Sbeck 	return uis->out_string;
746da347917Sbeck }
747da347917Sbeck 
748764af611Stedu const char *
749764af611Stedu UI_get0_action_string(UI_STRING *uis)
750da347917Sbeck {
751da347917Sbeck 	if (!uis)
752da347917Sbeck 		return NULL;
753764af611Stedu 	switch (uis->type) {
754da347917Sbeck 	case UIT_PROMPT:
755da347917Sbeck 	case UIT_BOOLEAN:
756da347917Sbeck 		return uis->_.boolean_data.action_desc;
757da347917Sbeck 	default:
758da347917Sbeck 		return NULL;
759da347917Sbeck 	}
760da347917Sbeck }
761da347917Sbeck 
762764af611Stedu const char *
763764af611Stedu UI_get0_result_string(UI_STRING *uis)
764da347917Sbeck {
765da347917Sbeck 	if (!uis)
766da347917Sbeck 		return NULL;
767764af611Stedu 	switch (uis->type) {
768da347917Sbeck 	case UIT_PROMPT:
769da347917Sbeck 	case UIT_VERIFY:
770da347917Sbeck 		return uis->result_buf;
771da347917Sbeck 	default:
772da347917Sbeck 		return NULL;
773da347917Sbeck 	}
774da347917Sbeck }
775da347917Sbeck 
776764af611Stedu const char *
777764af611Stedu UI_get0_test_string(UI_STRING *uis)
778da347917Sbeck {
779da347917Sbeck 	if (!uis)
780da347917Sbeck 		return NULL;
781764af611Stedu 	switch (uis->type) {
782da347917Sbeck 	case UIT_VERIFY:
783da347917Sbeck 		return uis->_.string_data.test_buf;
784da347917Sbeck 	default:
785da347917Sbeck 		return NULL;
786da347917Sbeck 	}
787da347917Sbeck }
788da347917Sbeck 
789764af611Stedu int
790764af611Stedu UI_get_result_minsize(UI_STRING *uis)
791da347917Sbeck {
792da347917Sbeck 	if (!uis)
793da347917Sbeck 		return -1;
794764af611Stedu 	switch (uis->type) {
795da347917Sbeck 	case UIT_PROMPT:
796da347917Sbeck 	case UIT_VERIFY:
797da347917Sbeck 		return uis->_.string_data.result_minsize;
798da347917Sbeck 	default:
799da347917Sbeck 		return -1;
800da347917Sbeck 	}
801da347917Sbeck }
802da347917Sbeck 
803764af611Stedu int
804764af611Stedu UI_get_result_maxsize(UI_STRING *uis)
805da347917Sbeck {
806da347917Sbeck 	if (!uis)
807da347917Sbeck 		return -1;
808764af611Stedu 	switch (uis->type) {
809da347917Sbeck 	case UIT_PROMPT:
810da347917Sbeck 	case UIT_VERIFY:
811da347917Sbeck 		return uis->_.string_data.result_maxsize;
812da347917Sbeck 	default:
813da347917Sbeck 		return -1;
814da347917Sbeck 	}
815da347917Sbeck }
816da347917Sbeck 
817764af611Stedu int
818764af611Stedu UI_set_result(UI *ui, UI_STRING *uis, const char *result)
819da347917Sbeck {
820da347917Sbeck 	int l = strlen(result);
821da347917Sbeck 
822da347917Sbeck 	ui->flags &= ~UI_FLAG_REDOABLE;
823da347917Sbeck 
824da347917Sbeck 	if (!uis)
825da347917Sbeck 		return -1;
826764af611Stedu 	switch (uis->type) {
827da347917Sbeck 	case UIT_PROMPT:
828da347917Sbeck 	case UIT_VERIFY:
829764af611Stedu 		if (l < uis->_.string_data.result_minsize) {
830da347917Sbeck 			ui->flags |= UI_FLAG_REDOABLE;
8310f637b92Sbeck 			UIerr(UI_F_UI_SET_RESULT,
8320f637b92Sbeck 			    UI_R_RESULT_TOO_SMALL);
8330f637b92Sbeck 			ERR_asprintf_error_data
8340f637b92Sbeck 			    ("You must type in %d to %d characters",
8350f637b92Sbeck 				uis->_.string_data.result_minsize,
8360f637b92Sbeck 				uis->_.string_data.result_maxsize);
837da347917Sbeck 			return -1;
838da347917Sbeck 		}
839764af611Stedu 		if (l > uis->_.string_data.result_maxsize) {
840da347917Sbeck 			ui->flags |= UI_FLAG_REDOABLE;
8410f637b92Sbeck 			UIerr(UI_F_UI_SET_RESULT,
8420f637b92Sbeck 			    UI_R_RESULT_TOO_LARGE);
8430f637b92Sbeck 			ERR_asprintf_error_data
8440f637b92Sbeck 			    ("You must type in %d to %d characters",
8450f637b92Sbeck 				uis->_.string_data.result_minsize,
8460f637b92Sbeck 				uis->_.string_data.result_maxsize);
847da347917Sbeck 			return -1;
848da347917Sbeck 		}
849764af611Stedu 		if (!uis->result_buf) {
850da347917Sbeck 			UIerr(UI_F_UI_SET_RESULT, UI_R_NO_RESULT_BUFFER);
851da347917Sbeck 			return -1;
852da347917Sbeck 		}
853143cedbbSbeck 		strlcpy(uis->result_buf, result,
854c52d3e9eSho 		    uis->_.string_data.result_maxsize + 1);
855da347917Sbeck 		break;
856da347917Sbeck 	case UIT_BOOLEAN:
857da347917Sbeck 		{
858da347917Sbeck 			const char *p;
859da347917Sbeck 
860764af611Stedu 			if (!uis->result_buf) {
861da347917Sbeck 				UIerr(UI_F_UI_SET_RESULT, UI_R_NO_RESULT_BUFFER);
862da347917Sbeck 				return -1;
863da347917Sbeck 			}
864da347917Sbeck 			uis->result_buf[0] = '\0';
865764af611Stedu 			for (p = result; *p; p++) {
866764af611Stedu 				if (strchr(uis->_.boolean_data.ok_chars, *p)) {
867da347917Sbeck 					uis->result_buf[0] =
868da347917Sbeck 					    uis->_.boolean_data.ok_chars[0];
869da347917Sbeck 					break;
870da347917Sbeck 				}
871764af611Stedu 				if (strchr(uis->_.boolean_data.cancel_chars, *p)) {
872da347917Sbeck 					uis->result_buf[0] =
873da347917Sbeck 					    uis->_.boolean_data.cancel_chars[0];
874da347917Sbeck 					break;
875da347917Sbeck 				}
876da347917Sbeck 			}
877da347917Sbeck 		default:
878da347917Sbeck 			break;
879da347917Sbeck 		}
880da347917Sbeck 	}
881da347917Sbeck 	return 0;
882da347917Sbeck }
883