1 /* crypto/ui/ui_lib.c -*- mode:C; c-file-style: "eay" -*- */
2 /* Written by Richard Levitte (richard@levitte.org) for the OpenSSL
5 /* ====================================================================
6 * Copyright (c) 2001 The OpenSSL Project. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
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
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/)"
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.
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.
34 * 6. Redistributions of any form whatsoever must retain the following
36 * "This product includes software developed by the OpenSSL Project
37 * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
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 * ====================================================================
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).
61 #include <openssl/e_os2.h>
62 #include <openssl/buffer.h>
63 #include <openssl/ui.h>
64 #include <openssl/err.h>
67 IMPLEMENT_STACK_OF(UI_STRING_ST
)
69 static const UI_METHOD
*default_UI_meth
=NULL
;
73 return(UI_new_method(NULL
));
76 UI
*UI_new_method(const UI_METHOD
*method
)
80 ret
=(UI
*)OPENSSL_malloc(sizeof(UI
));
83 UIerr(UI_F_UI_NEW_METHOD
,ERR_R_MALLOC_FAILURE
);
87 ret
->meth
=UI_get_default_method();
94 CRYPTO_new_ex_data(CRYPTO_EX_INDEX_UI
, ret
, &ret
->ex_data
);
98 static void free_string(UI_STRING
*uis
)
100 if (uis
->flags
& OUT_STRING_FREEABLE
)
102 OPENSSL_free((char *)uis
->out_string
);
106 OPENSSL_free((char *)uis
->_
.boolean_data
.action_desc
);
107 OPENSSL_free((char *)uis
->_
.boolean_data
.ok_chars
);
108 OPENSSL_free((char *)uis
->_
.boolean_data
.cancel_chars
);
121 sk_UI_STRING_pop_free(ui
->strings
,free_string
);
122 CRYPTO_free_ex_data(CRYPTO_EX_INDEX_UI
, ui
, &ui
->ex_data
);
126 static int allocate_string_stack(UI
*ui
)
128 if (ui
->strings
== NULL
)
130 ui
->strings
=sk_UI_STRING_new_null();
131 if (ui
->strings
== NULL
)
139 static UI_STRING
*general_allocate_prompt(UI
*ui
, const char *prompt
,
140 int prompt_freeable
, enum UI_string_types type
, int input_flags
,
143 UI_STRING
*ret
= NULL
;
147 UIerr(UI_F_GENERAL_ALLOCATE_PROMPT
,ERR_R_PASSED_NULL_PARAMETER
);
149 else if ((type
== UIT_PROMPT
|| type
== UIT_VERIFY
150 || type
== UIT_BOOLEAN
) && result_buf
== NULL
)
152 UIerr(UI_F_GENERAL_ALLOCATE_PROMPT
,UI_R_NO_RESULT_BUFFER
);
154 else if ((ret
= (UI_STRING
*)OPENSSL_malloc(sizeof(UI_STRING
))))
156 ret
->out_string
=prompt
;
157 ret
->flags
=prompt_freeable
? OUT_STRING_FREEABLE
: 0;
158 ret
->input_flags
=input_flags
;
160 ret
->result_buf
=result_buf
;
165 static int general_allocate_string(UI
*ui
, const char *prompt
,
166 int prompt_freeable
, enum UI_string_types type
, int input_flags
,
167 char *result_buf
, int minsize
, int maxsize
, const char *test_buf
)
170 UI_STRING
*s
= general_allocate_prompt(ui
, prompt
, prompt_freeable
,
171 type
, input_flags
, result_buf
);
175 if (allocate_string_stack(ui
) >= 0)
177 s
->_
.string_data
.result_minsize
=minsize
;
178 s
->_
.string_data
.result_maxsize
=maxsize
;
179 s
->_
.string_data
.test_buf
=test_buf
;
180 ret
=sk_UI_STRING_push(ui
->strings
, s
);
181 /* sk_push() returns 0 on error. Let's addapt that */
190 static int general_allocate_boolean(UI
*ui
,
191 const char *prompt
, const char *action_desc
,
192 const char *ok_chars
, const char *cancel_chars
,
193 int prompt_freeable
, enum UI_string_types type
, int input_flags
,
200 if (ok_chars
== NULL
)
202 UIerr(UI_F_GENERAL_ALLOCATE_BOOLEAN
,ERR_R_PASSED_NULL_PARAMETER
);
204 else if (cancel_chars
== NULL
)
206 UIerr(UI_F_GENERAL_ALLOCATE_BOOLEAN
,ERR_R_PASSED_NULL_PARAMETER
);
210 for(p
= ok_chars
; *p
; p
++)
212 if (strchr(cancel_chars
, *p
))
214 UIerr(UI_F_GENERAL_ALLOCATE_BOOLEAN
,
215 UI_R_COMMON_OK_AND_CANCEL_CHARACTERS
);
219 s
= general_allocate_prompt(ui
, prompt
, prompt_freeable
,
220 type
, input_flags
, result_buf
);
224 if (allocate_string_stack(ui
) >= 0)
226 s
->_
.boolean_data
.action_desc
= action_desc
;
227 s
->_
.boolean_data
.ok_chars
= ok_chars
;
228 s
->_
.boolean_data
.cancel_chars
= cancel_chars
;
229 ret
=sk_UI_STRING_push(ui
->strings
, s
);
230 /* sk_push() returns 0 on error.
241 /* Returns the index to the place in the stack or -1 for error. Uses a
242 direct reference to the prompt. */
243 int UI_add_input_string(UI
*ui
, const char *prompt
, int flags
,
244 char *result_buf
, int minsize
, int maxsize
)
246 return general_allocate_string(ui
, prompt
, 0,
247 UIT_PROMPT
, flags
, result_buf
, minsize
, maxsize
, NULL
);
250 /* Same as UI_add_input_string(), excepts it takes a copy of the prompt */
251 int UI_dup_input_string(UI
*ui
, const char *prompt
, int flags
,
252 char *result_buf
, int minsize
, int maxsize
)
254 char *prompt_copy
=NULL
;
258 prompt_copy
=BUF_strdup(prompt
);
259 if (prompt_copy
== NULL
)
261 UIerr(UI_F_UI_DUP_INPUT_STRING
,ERR_R_MALLOC_FAILURE
);
266 return general_allocate_string(ui
, prompt_copy
, 1,
267 UIT_PROMPT
, flags
, result_buf
, minsize
, maxsize
, NULL
);
270 int UI_add_verify_string(UI
*ui
, const char *prompt
, int flags
,
271 char *result_buf
, int minsize
, int maxsize
, const char *test_buf
)
273 return general_allocate_string(ui
, prompt
, 0,
274 UIT_VERIFY
, flags
, result_buf
, minsize
, maxsize
, test_buf
);
277 int UI_dup_verify_string(UI
*ui
, const char *prompt
, int flags
,
278 char *result_buf
, int minsize
, int maxsize
, const char *test_buf
)
280 char *prompt_copy
=NULL
;
284 prompt_copy
=BUF_strdup(prompt
);
285 if (prompt_copy
== NULL
)
287 UIerr(UI_F_UI_DUP_VERIFY_STRING
,ERR_R_MALLOC_FAILURE
);
292 return general_allocate_string(ui
, prompt_copy
, 1,
293 UIT_VERIFY
, flags
, result_buf
, minsize
, maxsize
, test_buf
);
296 int UI_add_input_boolean(UI
*ui
, const char *prompt
, const char *action_desc
,
297 const char *ok_chars
, const char *cancel_chars
,
298 int flags
, char *result_buf
)
300 return general_allocate_boolean(ui
, prompt
, action_desc
,
301 ok_chars
, cancel_chars
, 0, UIT_BOOLEAN
, flags
, result_buf
);
304 int UI_dup_input_boolean(UI
*ui
, const char *prompt
, const char *action_desc
,
305 const char *ok_chars
, const char *cancel_chars
,
306 int flags
, char *result_buf
)
308 char *prompt_copy
= NULL
;
309 char *action_desc_copy
= NULL
;
310 char *ok_chars_copy
= NULL
;
311 char *cancel_chars_copy
= NULL
;
315 prompt_copy
=BUF_strdup(prompt
);
316 if (prompt_copy
== NULL
)
318 UIerr(UI_F_UI_DUP_INPUT_BOOLEAN
,ERR_R_MALLOC_FAILURE
);
325 action_desc_copy
=BUF_strdup(action_desc
);
326 if (action_desc_copy
== NULL
)
328 UIerr(UI_F_UI_DUP_INPUT_BOOLEAN
,ERR_R_MALLOC_FAILURE
);
335 ok_chars_copy
=BUF_strdup(ok_chars
);
336 if (ok_chars_copy
== NULL
)
338 UIerr(UI_F_UI_DUP_INPUT_BOOLEAN
,ERR_R_MALLOC_FAILURE
);
345 cancel_chars_copy
=BUF_strdup(cancel_chars
);
346 if (cancel_chars_copy
== NULL
)
348 UIerr(UI_F_UI_DUP_INPUT_BOOLEAN
,ERR_R_MALLOC_FAILURE
);
353 return general_allocate_boolean(ui
, prompt_copy
, action_desc_copy
,
354 ok_chars_copy
, cancel_chars_copy
, 1, UIT_BOOLEAN
, flags
,
357 if (prompt_copy
) OPENSSL_free(prompt_copy
);
358 if (action_desc_copy
) OPENSSL_free(action_desc_copy
);
359 if (ok_chars_copy
) OPENSSL_free(ok_chars_copy
);
360 if (cancel_chars_copy
) OPENSSL_free(cancel_chars_copy
);
364 int UI_add_info_string(UI
*ui
, const char *text
)
366 return general_allocate_string(ui
, text
, 0, UIT_INFO
, 0, NULL
, 0, 0,
370 int UI_dup_info_string(UI
*ui
, const char *text
)
372 char *text_copy
=NULL
;
376 text_copy
=BUF_strdup(text
);
377 if (text_copy
== NULL
)
379 UIerr(UI_F_UI_DUP_INFO_STRING
,ERR_R_MALLOC_FAILURE
);
384 return general_allocate_string(ui
, text_copy
, 1, UIT_INFO
, 0, NULL
,
388 int UI_add_error_string(UI
*ui
, const char *text
)
390 return general_allocate_string(ui
, text
, 0, UIT_ERROR
, 0, NULL
, 0, 0,
394 int UI_dup_error_string(UI
*ui
, const char *text
)
396 char *text_copy
=NULL
;
400 text_copy
=BUF_strdup(text
);
401 if (text_copy
== NULL
)
403 UIerr(UI_F_UI_DUP_ERROR_STRING
,ERR_R_MALLOC_FAILURE
);
407 return general_allocate_string(ui
, text_copy
, 1, UIT_ERROR
, 0, NULL
,
411 char *UI_construct_prompt(UI
*ui
, const char *object_desc
,
412 const char *object_name
)
416 if (ui
->meth
->ui_construct_prompt
)
417 prompt
= ui
->meth
->ui_construct_prompt(ui
,
418 object_desc
, object_name
);
421 char prompt1
[] = "Enter ";
422 char prompt2
[] = " for ";
423 char prompt3
[] = ":";
426 if (object_desc
== NULL
)
428 len
= sizeof(prompt1
) - 1 + strlen(object_desc
);
430 len
+= sizeof(prompt2
) - 1 + strlen(object_name
);
431 len
+= sizeof(prompt3
) - 1;
433 prompt
= (char *)OPENSSL_malloc(len
+ 1);
434 BUF_strlcpy(prompt
, prompt1
, len
+ 1);
435 BUF_strlcat(prompt
, object_desc
, len
+ 1);
438 BUF_strlcat(prompt
, prompt2
, len
+ 1);
439 BUF_strlcat(prompt
, object_name
, len
+ 1);
441 BUF_strlcat(prompt
, prompt3
, len
+ 1);
446 void *UI_add_user_data(UI
*ui
, void *user_data
)
448 void *old_data
= ui
->user_data
;
449 ui
->user_data
= user_data
;
453 void *UI_get0_user_data(UI
*ui
)
455 return ui
->user_data
;
458 const char *UI_get0_result(UI
*ui
, int i
)
462 UIerr(UI_F_UI_GET0_RESULT
,UI_R_INDEX_TOO_SMALL
);
465 if (i
>= sk_UI_STRING_num(ui
->strings
))
467 UIerr(UI_F_UI_GET0_RESULT
,UI_R_INDEX_TOO_LARGE
);
470 return UI_get0_result_string(sk_UI_STRING_value(ui
->strings
, i
));
473 static int print_error(const char *str
, size_t len
, UI
*ui
)
477 memset(&uis
, 0, sizeof(uis
));
478 uis
.type
= UIT_ERROR
;
479 uis
.out_string
= str
;
481 if (ui
->meth
->ui_write_string
482 && !ui
->meth
->ui_write_string(ui
, &uis
))
487 int UI_process(UI
*ui
)
491 if (ui
->meth
->ui_open_session
&& !ui
->meth
->ui_open_session(ui
))
494 if (ui
->flags
& UI_FLAG_PRINT_ERRORS
)
496 (int (*)(const char *, size_t, void *))print_error
,
499 for(i
=0; i
<sk_UI_STRING_num(ui
->strings
); i
++)
501 if (ui
->meth
->ui_write_string
502 && !ui
->meth
->ui_write_string(ui
,
503 sk_UI_STRING_value(ui
->strings
, i
)))
510 if (ui
->meth
->ui_flush
)
511 switch(ui
->meth
->ui_flush(ui
))
513 case -1: /* Interrupt/Cancel/something... */
519 default: /* Success */
524 for(i
=0; i
<sk_UI_STRING_num(ui
->strings
); i
++)
526 if (ui
->meth
->ui_read_string
)
528 switch(ui
->meth
->ui_read_string(ui
,
529 sk_UI_STRING_value(ui
->strings
, i
)))
531 case -1: /* Interrupt/Cancel/something... */
537 default: /* Success */
544 if (ui
->meth
->ui_close_session
&& !ui
->meth
->ui_close_session(ui
))
549 int UI_ctrl(UI
*ui
, int cmd
, long i
, void *p
, void (*f
)(void))
553 UIerr(UI_F_UI_CTRL
,ERR_R_PASSED_NULL_PARAMETER
);
558 case UI_CTRL_PRINT_ERRORS
:
560 int save_flag
= !!(ui
->flags
& UI_FLAG_PRINT_ERRORS
);
562 ui
->flags
|= UI_FLAG_PRINT_ERRORS
;
564 ui
->flags
&= ~UI_FLAG_PRINT_ERRORS
;
567 case UI_CTRL_IS_REDOABLE
:
568 return !!(ui
->flags
& UI_FLAG_REDOABLE
);
572 UIerr(UI_F_UI_CTRL
,UI_R_UNKNOWN_CONTROL_COMMAND
);
576 int UI_get_ex_new_index(long argl
, void *argp
, CRYPTO_EX_new
*new_func
,
577 CRYPTO_EX_dup
*dup_func
, CRYPTO_EX_free
*free_func
)
579 return CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_UI
, argl
, argp
,
580 new_func
, dup_func
, free_func
);
583 int UI_set_ex_data(UI
*r
, int idx
, void *arg
)
585 return(CRYPTO_set_ex_data(&r
->ex_data
,idx
,arg
));
588 void *UI_get_ex_data(UI
*r
, int idx
)
590 return(CRYPTO_get_ex_data(&r
->ex_data
,idx
));
593 void UI_set_default_method(const UI_METHOD
*meth
)
595 default_UI_meth
=meth
;
598 const UI_METHOD
*UI_get_default_method(void)
600 if (default_UI_meth
== NULL
)
602 default_UI_meth
=UI_OpenSSL();
604 return default_UI_meth
;
607 const UI_METHOD
*UI_get_method(UI
*ui
)
612 const UI_METHOD
*UI_set_method(UI
*ui
, const UI_METHOD
*meth
)
619 UI_METHOD
*UI_create_method(char *name
)
621 UI_METHOD
*ui_method
= (UI_METHOD
*)OPENSSL_malloc(sizeof(UI_METHOD
));
625 memset(ui_method
, 0, sizeof(*ui_method
));
626 ui_method
->name
= BUF_strdup(name
);
631 /* BIG FSCKING WARNING!!!! If you use this on a statically allocated method
632 (that is, it hasn't been allocated using UI_create_method(), you deserve
633 anything Murphy can throw at you and more! You have been warned. */
634 void UI_destroy_method(UI_METHOD
*ui_method
)
636 OPENSSL_free(ui_method
->name
);
637 ui_method
->name
= NULL
;
638 OPENSSL_free(ui_method
);
641 int UI_method_set_opener(UI_METHOD
*method
, int (*opener
)(UI
*ui
))
645 method
->ui_open_session
= opener
;
652 int UI_method_set_writer(UI_METHOD
*method
, int (*writer
)(UI
*ui
, UI_STRING
*uis
))
656 method
->ui_write_string
= writer
;
663 int UI_method_set_flusher(UI_METHOD
*method
, int (*flusher
)(UI
*ui
))
667 method
->ui_flush
= flusher
;
674 int UI_method_set_reader(UI_METHOD
*method
, int (*reader
)(UI
*ui
, UI_STRING
*uis
))
678 method
->ui_read_string
= reader
;
685 int UI_method_set_closer(UI_METHOD
*method
, int (*closer
)(UI
*ui
))
689 method
->ui_close_session
= closer
;
696 int UI_method_set_prompt_constructor(UI_METHOD
*method
, char *(*prompt_constructor
)(UI
* ui
, const char* object_desc
, const char* object_name
))
700 method
->ui_construct_prompt
= prompt_constructor
;
707 int (*UI_method_get_opener(UI_METHOD
*method
))(UI
*)
710 return method
->ui_open_session
;
715 int (*UI_method_get_writer(UI_METHOD
*method
))(UI
*,UI_STRING
*)
718 return method
->ui_write_string
;
723 int (*UI_method_get_flusher(UI_METHOD
*method
))(UI
*)
726 return method
->ui_flush
;
731 int (*UI_method_get_reader(UI_METHOD
*method
))(UI
*,UI_STRING
*)
734 return method
->ui_read_string
;
739 int (*UI_method_get_closer(UI_METHOD
*method
))(UI
*)
742 return method
->ui_close_session
;
747 char* (*UI_method_get_prompt_constructor(UI_METHOD
*method
))(UI
*, const char*, const char*)
750 return method
->ui_construct_prompt
;
755 enum UI_string_types
UI_get_string_type(UI_STRING
*uis
)
762 int UI_get_input_flags(UI_STRING
*uis
)
766 return uis
->input_flags
;
769 const char *UI_get0_output_string(UI_STRING
*uis
)
773 return uis
->out_string
;
776 const char *UI_get0_action_string(UI_STRING
*uis
)
784 return uis
->_
.boolean_data
.action_desc
;
790 const char *UI_get0_result_string(UI_STRING
*uis
)
798 return uis
->result_buf
;
804 const char *UI_get0_test_string(UI_STRING
*uis
)
811 return uis
->_
.string_data
.test_buf
;
817 int UI_get_result_minsize(UI_STRING
*uis
)
825 return uis
->_
.string_data
.result_minsize
;
831 int UI_get_result_maxsize(UI_STRING
*uis
)
839 return uis
->_
.string_data
.result_maxsize
;
845 int UI_set_result(UI
*ui
, UI_STRING
*uis
, const char *result
)
847 int l
= strlen(result
);
849 ui
->flags
&= ~UI_FLAG_REDOABLE
;
858 char number1
[DECIMAL_SIZE(uis
->_
.string_data
.result_minsize
)+1];
859 char number2
[DECIMAL_SIZE(uis
->_
.string_data
.result_maxsize
)+1];
861 BIO_snprintf(number1
, sizeof(number1
), "%d",
862 uis
->_
.string_data
.result_minsize
);
863 BIO_snprintf(number2
, sizeof(number2
), "%d",
864 uis
->_
.string_data
.result_maxsize
);
866 if (l
< uis
->_
.string_data
.result_minsize
)
868 ui
->flags
|= UI_FLAG_REDOABLE
;
869 UIerr(UI_F_UI_SET_RESULT
,UI_R_RESULT_TOO_SMALL
);
870 ERR_add_error_data(5,"You must type in ",
871 number1
," to ",number2
," characters");
874 if (l
> uis
->_
.string_data
.result_maxsize
)
876 ui
->flags
|= UI_FLAG_REDOABLE
;
877 UIerr(UI_F_UI_SET_RESULT
,UI_R_RESULT_TOO_LARGE
);
878 ERR_add_error_data(5,"You must type in ",
879 number1
," to ",number2
," characters");
884 if (!uis
->result_buf
)
886 UIerr(UI_F_UI_SET_RESULT
,UI_R_NO_RESULT_BUFFER
);
890 BUF_strlcpy(uis
->result_buf
, result
,
891 uis
->_
.string_data
.result_maxsize
+ 1);
897 if (!uis
->result_buf
)
899 UIerr(UI_F_UI_SET_RESULT
,UI_R_NO_RESULT_BUFFER
);
903 uis
->result_buf
[0] = '\0';
904 for(p
= result
; *p
; p
++)
906 if (strchr(uis
->_
.boolean_data
.ok_chars
, *p
))
909 uis
->_
.boolean_data
.ok_chars
[0];
912 if (strchr(uis
->_
.boolean_data
.cancel_chars
, *p
))
915 uis
->_
.boolean_data
.cancel_chars
[0];