]>
Commit | Line | Data |
---|---|---|
0f113f3e | 1 | /* |
33388b44 | 2 | * Copyright 2001-2020 The OpenSSL Project Authors. All Rights Reserved. |
a63d5eaa | 3 | * |
55e0593c | 4 | * Licensed under the Apache License 2.0 (the "License"). You may not use |
aa6bb135 RS |
5 | * this file except in compliance with the License. You can obtain a copy |
6 | * in the file LICENSE in the source distribution or at | |
7 | * https://www.openssl.org/source/license.html | |
a63d5eaa RL |
8 | */ |
9 | ||
10 | #include <string.h> | |
b39fc560 | 11 | #include "internal/cryptlib.h" |
eb929eef RL |
12 | #include <openssl/e_os2.h> |
13 | #include <openssl/buffer.h> | |
a63d5eaa RL |
14 | #include <openssl/ui.h> |
15 | #include <openssl/err.h> | |
706457b7 | 16 | #include "ui_local.h" |
a63d5eaa | 17 | |
852c2ed2 RS |
18 | DEFINE_STACK_OF(UI_STRING) |
19 | ||
a63d5eaa | 20 | UI *UI_new(void) |
0f113f3e | 21 | { |
26a7d938 | 22 | return UI_new_method(NULL); |
0f113f3e | 23 | } |
a63d5eaa RL |
24 | |
25 | UI *UI_new_method(const UI_METHOD *method) | |
0f113f3e | 26 | { |
64b25758 | 27 | UI *ret = OPENSSL_zalloc(sizeof(*ret)); |
0f113f3e | 28 | |
0f113f3e MC |
29 | if (ret == NULL) { |
30 | UIerr(UI_F_UI_NEW_METHOD, ERR_R_MALLOC_FAILURE); | |
31 | return NULL; | |
32 | } | |
41cfbccc AG |
33 | |
34 | ret->lock = CRYPTO_THREAD_lock_new(); | |
35 | if (ret->lock == NULL) { | |
36 | UIerr(UI_F_UI_NEW_METHOD, ERR_R_MALLOC_FAILURE); | |
37 | OPENSSL_free(ret); | |
38 | return NULL; | |
39 | } | |
40 | ||
0f113f3e | 41 | if (method == NULL) |
48feaceb RL |
42 | method = UI_get_default_method(); |
43 | if (method == NULL) | |
44 | method = UI_null(); | |
45 | ret->meth = method; | |
0f113f3e | 46 | |
25a807bc F |
47 | if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_UI, ret, &ret->ex_data)) { |
48 | OPENSSL_free(ret); | |
49 | return NULL; | |
50 | } | |
0f113f3e MC |
51 | return ret; |
52 | } | |
a63d5eaa | 53 | |
d6f188be | 54 | static void free_string(UI_STRING *uis) |
0f113f3e MC |
55 | { |
56 | if (uis->flags & OUT_STRING_FREEABLE) { | |
57 | OPENSSL_free((char *)uis->out_string); | |
58 | switch (uis->type) { | |
59 | case UIT_BOOLEAN: | |
60 | OPENSSL_free((char *)uis->_.boolean_data.action_desc); | |
61 | OPENSSL_free((char *)uis->_.boolean_data.ok_chars); | |
62 | OPENSSL_free((char *)uis->_.boolean_data.cancel_chars); | |
63 | break; | |
f3b3d7f0 RS |
64 | case UIT_NONE: |
65 | case UIT_PROMPT: | |
66 | case UIT_VERIFY: | |
67 | case UIT_ERROR: | |
68 | case UIT_INFO: | |
0f113f3e MC |
69 | break; |
70 | } | |
71 | } | |
72 | OPENSSL_free(uis); | |
73 | } | |
a63d5eaa RL |
74 | |
75 | void UI_free(UI *ui) | |
0f113f3e MC |
76 | { |
77 | if (ui == NULL) | |
78 | return; | |
545360c4 RL |
79 | if ((ui->flags & UI_FLAG_DUPL_DATA) != 0) { |
80 | ui->meth->ui_destroy_data(ui, ui->user_data); | |
81 | } | |
0f113f3e MC |
82 | sk_UI_STRING_pop_free(ui->strings, free_string); |
83 | CRYPTO_free_ex_data(CRYPTO_EX_INDEX_UI, ui, &ui->ex_data); | |
41cfbccc | 84 | CRYPTO_THREAD_lock_free(ui->lock); |
0f113f3e MC |
85 | OPENSSL_free(ui); |
86 | } | |
a63d5eaa RL |
87 | |
88 | static int allocate_string_stack(UI *ui) | |
0f113f3e MC |
89 | { |
90 | if (ui->strings == NULL) { | |
91 | ui->strings = sk_UI_STRING_new_null(); | |
92 | if (ui->strings == NULL) { | |
93 | return -1; | |
94 | } | |
95 | } | |
96 | return 0; | |
97 | } | |
a63d5eaa | 98 | |
2d2ed9df | 99 | static UI_STRING *general_allocate_prompt(UI *ui, const char *prompt, |
0f113f3e MC |
100 | int prompt_freeable, |
101 | enum UI_string_types type, | |
102 | int input_flags, char *result_buf) | |
103 | { | |
104 | UI_STRING *ret = NULL; | |
105 | ||
106 | if (prompt == NULL) { | |
107 | UIerr(UI_F_GENERAL_ALLOCATE_PROMPT, ERR_R_PASSED_NULL_PARAMETER); | |
108 | } else if ((type == UIT_PROMPT || type == UIT_VERIFY | |
109 | || type == UIT_BOOLEAN) && result_buf == NULL) { | |
110 | UIerr(UI_F_GENERAL_ALLOCATE_PROMPT, UI_R_NO_RESULT_BUFFER); | |
90945fa3 | 111 | } else if ((ret = OPENSSL_malloc(sizeof(*ret))) != NULL) { |
0f113f3e MC |
112 | ret->out_string = prompt; |
113 | ret->flags = prompt_freeable ? OUT_STRING_FREEABLE : 0; | |
114 | ret->input_flags = input_flags; | |
115 | ret->type = type; | |
116 | ret->result_buf = result_buf; | |
117 | } | |
118 | return ret; | |
119 | } | |
2d2ed9df | 120 | |
a63d5eaa | 121 | static int general_allocate_string(UI *ui, const char *prompt, |
0f113f3e MC |
122 | int prompt_freeable, |
123 | enum UI_string_types type, int input_flags, | |
124 | char *result_buf, int minsize, int maxsize, | |
125 | const char *test_buf) | |
126 | { | |
127 | int ret = -1; | |
128 | UI_STRING *s = general_allocate_prompt(ui, prompt, prompt_freeable, | |
129 | type, input_flags, result_buf); | |
130 | ||
120fb9e4 | 131 | if (s != NULL) { |
0f113f3e MC |
132 | if (allocate_string_stack(ui) >= 0) { |
133 | s->_.string_data.result_minsize = minsize; | |
134 | s->_.string_data.result_maxsize = maxsize; | |
135 | s->_.string_data.test_buf = test_buf; | |
136 | ret = sk_UI_STRING_push(ui->strings, s); | |
0d4fb843 | 137 | /* sk_push() returns 0 on error. Let's adapt that */ |
68efafc5 | 138 | if (ret <= 0) { |
0f113f3e | 139 | ret--; |
68efafc5 F |
140 | free_string(s); |
141 | } | |
0f113f3e MC |
142 | } else |
143 | free_string(s); | |
144 | } | |
145 | return ret; | |
146 | } | |
2d2ed9df RL |
147 | |
148 | static int general_allocate_boolean(UI *ui, | |
0f113f3e MC |
149 | const char *prompt, |
150 | const char *action_desc, | |
151 | const char *ok_chars, | |
152 | const char *cancel_chars, | |
153 | int prompt_freeable, | |
154 | enum UI_string_types type, | |
155 | int input_flags, char *result_buf) | |
156 | { | |
157 | int ret = -1; | |
158 | UI_STRING *s; | |
159 | const char *p; | |
160 | ||
161 | if (ok_chars == NULL) { | |
162 | UIerr(UI_F_GENERAL_ALLOCATE_BOOLEAN, ERR_R_PASSED_NULL_PARAMETER); | |
163 | } else if (cancel_chars == NULL) { | |
164 | UIerr(UI_F_GENERAL_ALLOCATE_BOOLEAN, ERR_R_PASSED_NULL_PARAMETER); | |
165 | } else { | |
120fb9e4 RL |
166 | for (p = ok_chars; *p != '\0'; p++) { |
167 | if (strchr(cancel_chars, *p) != NULL) { | |
0f113f3e MC |
168 | UIerr(UI_F_GENERAL_ALLOCATE_BOOLEAN, |
169 | UI_R_COMMON_OK_AND_CANCEL_CHARACTERS); | |
170 | } | |
171 | } | |
172 | ||
173 | s = general_allocate_prompt(ui, prompt, prompt_freeable, | |
174 | type, input_flags, result_buf); | |
175 | ||
120fb9e4 | 176 | if (s != NULL) { |
0f113f3e MC |
177 | if (allocate_string_stack(ui) >= 0) { |
178 | s->_.boolean_data.action_desc = action_desc; | |
179 | s->_.boolean_data.ok_chars = ok_chars; | |
180 | s->_.boolean_data.cancel_chars = cancel_chars; | |
181 | ret = sk_UI_STRING_push(ui->strings, s); | |
182 | /* | |
0d4fb843 | 183 | * sk_push() returns 0 on error. Let's adapt that |
0f113f3e | 184 | */ |
68efafc5 | 185 | if (ret <= 0) { |
0f113f3e | 186 | ret--; |
68efafc5 F |
187 | free_string(s); |
188 | } | |
0f113f3e MC |
189 | } else |
190 | free_string(s); | |
191 | } | |
192 | } | |
193 | return ret; | |
194 | } | |
195 | ||
196 | /* | |
197 | * Returns the index to the place in the stack or -1 for error. Uses a | |
198 | * direct reference to the prompt. | |
199 | */ | |
9ad0f681 | 200 | int UI_add_input_string(UI *ui, const char *prompt, int flags, |
0f113f3e MC |
201 | char *result_buf, int minsize, int maxsize) |
202 | { | |
203 | return general_allocate_string(ui, prompt, 0, | |
204 | UIT_PROMPT, flags, result_buf, minsize, | |
205 | maxsize, NULL); | |
206 | } | |
a63d5eaa RL |
207 | |
208 | /* Same as UI_add_input_string(), excepts it takes a copy of the prompt */ | |
9ad0f681 | 209 | int UI_dup_input_string(UI *ui, const char *prompt, int flags, |
0f113f3e MC |
210 | char *result_buf, int minsize, int maxsize) |
211 | { | |
212 | char *prompt_copy = NULL; | |
213 | ||
120fb9e4 | 214 | if (prompt != NULL) { |
7644a9ae | 215 | prompt_copy = OPENSSL_strdup(prompt); |
0f113f3e MC |
216 | if (prompt_copy == NULL) { |
217 | UIerr(UI_F_UI_DUP_INPUT_STRING, ERR_R_MALLOC_FAILURE); | |
218 | return 0; | |
219 | } | |
220 | } | |
221 | ||
222 | return general_allocate_string(ui, prompt_copy, 1, | |
223 | UIT_PROMPT, flags, result_buf, minsize, | |
224 | maxsize, NULL); | |
225 | } | |
a63d5eaa | 226 | |
9ad0f681 | 227 | int UI_add_verify_string(UI *ui, const char *prompt, int flags, |
0f113f3e MC |
228 | char *result_buf, int minsize, int maxsize, |
229 | const char *test_buf) | |
230 | { | |
231 | return general_allocate_string(ui, prompt, 0, | |
232 | UIT_VERIFY, flags, result_buf, minsize, | |
233 | maxsize, test_buf); | |
234 | } | |
a63d5eaa | 235 | |
9ad0f681 | 236 | int UI_dup_verify_string(UI *ui, const char *prompt, int flags, |
0f113f3e MC |
237 | char *result_buf, int minsize, int maxsize, |
238 | const char *test_buf) | |
239 | { | |
240 | char *prompt_copy = NULL; | |
241 | ||
120fb9e4 | 242 | if (prompt != NULL) { |
7644a9ae | 243 | prompt_copy = OPENSSL_strdup(prompt); |
0f113f3e MC |
244 | if (prompt_copy == NULL) { |
245 | UIerr(UI_F_UI_DUP_VERIFY_STRING, ERR_R_MALLOC_FAILURE); | |
246 | return -1; | |
247 | } | |
248 | } | |
249 | ||
250 | return general_allocate_string(ui, prompt_copy, 1, | |
251 | UIT_VERIFY, flags, result_buf, minsize, | |
252 | maxsize, test_buf); | |
253 | } | |
a63d5eaa | 254 | |
2d2ed9df | 255 | int UI_add_input_boolean(UI *ui, const char *prompt, const char *action_desc, |
0f113f3e MC |
256 | const char *ok_chars, const char *cancel_chars, |
257 | int flags, char *result_buf) | |
258 | { | |
259 | return general_allocate_boolean(ui, prompt, action_desc, | |
260 | ok_chars, cancel_chars, 0, UIT_BOOLEAN, | |
261 | flags, result_buf); | |
262 | } | |
2d2ed9df RL |
263 | |
264 | int UI_dup_input_boolean(UI *ui, const char *prompt, const char *action_desc, | |
0f113f3e MC |
265 | const char *ok_chars, const char *cancel_chars, |
266 | int flags, char *result_buf) | |
267 | { | |
268 | char *prompt_copy = NULL; | |
269 | char *action_desc_copy = NULL; | |
270 | char *ok_chars_copy = NULL; | |
271 | char *cancel_chars_copy = NULL; | |
272 | ||
120fb9e4 | 273 | if (prompt != NULL) { |
7644a9ae | 274 | prompt_copy = OPENSSL_strdup(prompt); |
0f113f3e MC |
275 | if (prompt_copy == NULL) { |
276 | UIerr(UI_F_UI_DUP_INPUT_BOOLEAN, ERR_R_MALLOC_FAILURE); | |
277 | goto err; | |
278 | } | |
279 | } | |
280 | ||
120fb9e4 | 281 | if (action_desc != NULL) { |
7644a9ae | 282 | action_desc_copy = OPENSSL_strdup(action_desc); |
0f113f3e MC |
283 | if (action_desc_copy == NULL) { |
284 | UIerr(UI_F_UI_DUP_INPUT_BOOLEAN, ERR_R_MALLOC_FAILURE); | |
285 | goto err; | |
286 | } | |
287 | } | |
288 | ||
120fb9e4 | 289 | if (ok_chars != NULL) { |
7644a9ae | 290 | ok_chars_copy = OPENSSL_strdup(ok_chars); |
0f113f3e MC |
291 | if (ok_chars_copy == NULL) { |
292 | UIerr(UI_F_UI_DUP_INPUT_BOOLEAN, ERR_R_MALLOC_FAILURE); | |
293 | goto err; | |
294 | } | |
295 | } | |
296 | ||
120fb9e4 | 297 | if (cancel_chars != NULL) { |
7644a9ae | 298 | cancel_chars_copy = OPENSSL_strdup(cancel_chars); |
0f113f3e MC |
299 | if (cancel_chars_copy == NULL) { |
300 | UIerr(UI_F_UI_DUP_INPUT_BOOLEAN, ERR_R_MALLOC_FAILURE); | |
301 | goto err; | |
302 | } | |
303 | } | |
304 | ||
305 | return general_allocate_boolean(ui, prompt_copy, action_desc_copy, | |
306 | ok_chars_copy, cancel_chars_copy, 1, | |
307 | UIT_BOOLEAN, flags, result_buf); | |
2d2ed9df | 308 | err: |
b548a1f1 RS |
309 | OPENSSL_free(prompt_copy); |
310 | OPENSSL_free(action_desc_copy); | |
311 | OPENSSL_free(ok_chars_copy); | |
312 | OPENSSL_free(cancel_chars_copy); | |
0f113f3e MC |
313 | return -1; |
314 | } | |
2d2ed9df | 315 | |
a63d5eaa | 316 | int UI_add_info_string(UI *ui, const char *text) |
0f113f3e MC |
317 | { |
318 | return general_allocate_string(ui, text, 0, UIT_INFO, 0, NULL, 0, 0, | |
319 | NULL); | |
320 | } | |
a63d5eaa RL |
321 | |
322 | int UI_dup_info_string(UI *ui, const char *text) | |
0f113f3e MC |
323 | { |
324 | char *text_copy = NULL; | |
325 | ||
120fb9e4 | 326 | if (text != NULL) { |
7644a9ae | 327 | text_copy = OPENSSL_strdup(text); |
0f113f3e MC |
328 | if (text_copy == NULL) { |
329 | UIerr(UI_F_UI_DUP_INFO_STRING, ERR_R_MALLOC_FAILURE); | |
330 | return -1; | |
331 | } | |
332 | } | |
333 | ||
334 | return general_allocate_string(ui, text_copy, 1, UIT_INFO, 0, NULL, | |
335 | 0, 0, NULL); | |
336 | } | |
a63d5eaa RL |
337 | |
338 | int UI_add_error_string(UI *ui, const char *text) | |
0f113f3e MC |
339 | { |
340 | return general_allocate_string(ui, text, 0, UIT_ERROR, 0, NULL, 0, 0, | |
341 | NULL); | |
342 | } | |
a63d5eaa RL |
343 | |
344 | int UI_dup_error_string(UI *ui, const char *text) | |
0f113f3e MC |
345 | { |
346 | char *text_copy = NULL; | |
347 | ||
120fb9e4 | 348 | if (text != NULL) { |
7644a9ae | 349 | text_copy = OPENSSL_strdup(text); |
0f113f3e MC |
350 | if (text_copy == NULL) { |
351 | UIerr(UI_F_UI_DUP_ERROR_STRING, ERR_R_MALLOC_FAILURE); | |
352 | return -1; | |
353 | } | |
354 | } | |
355 | return general_allocate_string(ui, text_copy, 1, UIT_ERROR, 0, NULL, | |
356 | 0, 0, NULL); | |
357 | } | |
9ad0f681 RL |
358 | |
359 | char *UI_construct_prompt(UI *ui, const char *object_desc, | |
0f113f3e MC |
360 | const char *object_name) |
361 | { | |
362 | char *prompt = NULL; | |
363 | ||
120fb9e4 | 364 | if (ui->meth->ui_construct_prompt != NULL) |
0f113f3e MC |
365 | prompt = ui->meth->ui_construct_prompt(ui, object_desc, object_name); |
366 | else { | |
367 | char prompt1[] = "Enter "; | |
368 | char prompt2[] = " for "; | |
369 | char prompt3[] = ":"; | |
370 | int len = 0; | |
371 | ||
372 | if (object_desc == NULL) | |
373 | return NULL; | |
374 | len = sizeof(prompt1) - 1 + strlen(object_desc); | |
120fb9e4 | 375 | if (object_name != NULL) |
0f113f3e MC |
376 | len += sizeof(prompt2) - 1 + strlen(object_name); |
377 | len += sizeof(prompt3) - 1; | |
378 | ||
cdb10bae RS |
379 | if ((prompt = OPENSSL_malloc(len + 1)) == NULL) { |
380 | UIerr(UI_F_UI_CONSTRUCT_PROMPT, ERR_R_MALLOC_FAILURE); | |
0f113f3e | 381 | return NULL; |
cdb10bae | 382 | } |
7644a9ae RS |
383 | OPENSSL_strlcpy(prompt, prompt1, len + 1); |
384 | OPENSSL_strlcat(prompt, object_desc, len + 1); | |
120fb9e4 | 385 | if (object_name != NULL) { |
7644a9ae RS |
386 | OPENSSL_strlcat(prompt, prompt2, len + 1); |
387 | OPENSSL_strlcat(prompt, object_name, len + 1); | |
0f113f3e | 388 | } |
7644a9ae | 389 | OPENSSL_strlcat(prompt, prompt3, len + 1); |
0f113f3e MC |
390 | } |
391 | return prompt; | |
392 | } | |
a63d5eaa | 393 | |
1e7e62f8 | 394 | void *UI_add_user_data(UI *ui, void *user_data) |
0f113f3e MC |
395 | { |
396 | void *old_data = ui->user_data; | |
545360c4 RL |
397 | |
398 | if ((ui->flags & UI_FLAG_DUPL_DATA) != 0) { | |
399 | ui->meth->ui_destroy_data(ui, old_data); | |
400 | old_data = NULL; | |
401 | } | |
0f113f3e | 402 | ui->user_data = user_data; |
545360c4 | 403 | ui->flags &= ~UI_FLAG_DUPL_DATA; |
0f113f3e MC |
404 | return old_data; |
405 | } | |
1e7e62f8 | 406 | |
545360c4 RL |
407 | int UI_dup_user_data(UI *ui, void *user_data) |
408 | { | |
409 | void *duplicate = NULL; | |
410 | ||
411 | if (ui->meth->ui_duplicate_data == NULL | |
412 | || ui->meth->ui_destroy_data == NULL) { | |
413 | UIerr(UI_F_UI_DUP_USER_DATA, UI_R_USER_DATA_DUPLICATION_UNSUPPORTED); | |
414 | return -1; | |
415 | } | |
416 | ||
417 | duplicate = ui->meth->ui_duplicate_data(ui, user_data); | |
418 | if (duplicate == NULL) { | |
419 | UIerr(UI_F_UI_DUP_USER_DATA, ERR_R_MALLOC_FAILURE); | |
420 | return -1; | |
421 | } | |
422 | ||
423 | (void)UI_add_user_data(ui, duplicate); | |
424 | ui->flags |= UI_FLAG_DUPL_DATA; | |
425 | ||
426 | return 0; | |
427 | } | |
428 | ||
1e7e62f8 | 429 | void *UI_get0_user_data(UI *ui) |
0f113f3e MC |
430 | { |
431 | return ui->user_data; | |
432 | } | |
1e7e62f8 | 433 | |
a63d5eaa | 434 | const char *UI_get0_result(UI *ui, int i) |
0f113f3e MC |
435 | { |
436 | if (i < 0) { | |
437 | UIerr(UI_F_UI_GET0_RESULT, UI_R_INDEX_TOO_SMALL); | |
438 | return NULL; | |
439 | } | |
440 | if (i >= sk_UI_STRING_num(ui->strings)) { | |
441 | UIerr(UI_F_UI_GET0_RESULT, UI_R_INDEX_TOO_LARGE); | |
442 | return NULL; | |
443 | } | |
444 | return UI_get0_result_string(sk_UI_STRING_value(ui->strings, i)); | |
445 | } | |
a63d5eaa | 446 | |
4e049e2c RL |
447 | int UI_get_result_length(UI *ui, int i) |
448 | { | |
449 | if (i < 0) { | |
450 | UIerr(UI_F_UI_GET_RESULT_LENGTH, UI_R_INDEX_TOO_SMALL); | |
451 | return -1; | |
452 | } | |
453 | if (i >= sk_UI_STRING_num(ui->strings)) { | |
454 | UIerr(UI_F_UI_GET_RESULT_LENGTH, UI_R_INDEX_TOO_LARGE); | |
455 | return -1; | |
456 | } | |
457 | return UI_get_result_string_length(sk_UI_STRING_value(ui->strings, i)); | |
458 | } | |
459 | ||
2d2ed9df | 460 | static int print_error(const char *str, size_t len, UI *ui) |
0f113f3e MC |
461 | { |
462 | UI_STRING uis; | |
2d2ed9df | 463 | |
0f113f3e MC |
464 | memset(&uis, 0, sizeof(uis)); |
465 | uis.type = UIT_ERROR; | |
466 | uis.out_string = str; | |
2d2ed9df | 467 | |
120fb9e4 RL |
468 | if (ui->meth->ui_write_string != NULL |
469 | && ui->meth->ui_write_string(ui, &uis) <= 0) | |
0f113f3e MC |
470 | return -1; |
471 | return 0; | |
472 | } | |
2d2ed9df | 473 | |
a63d5eaa | 474 | int UI_process(UI *ui) |
0f113f3e MC |
475 | { |
476 | int i, ok = 0; | |
0a687ab0 | 477 | const char *state = "processing"; |
2d2ed9df | 478 | |
120fb9e4 RL |
479 | if (ui->meth->ui_open_session != NULL |
480 | && ui->meth->ui_open_session(ui) <= 0) { | |
0a687ab0 RL |
481 | state = "opening session"; |
482 | ok = -1; | |
483 | goto err; | |
484 | } | |
0f113f3e MC |
485 | |
486 | if (ui->flags & UI_FLAG_PRINT_ERRORS) | |
487 | ERR_print_errors_cb((int (*)(const char *, size_t, void *)) | |
488 | print_error, (void *)ui); | |
489 | ||
490 | for (i = 0; i < sk_UI_STRING_num(ui->strings); i++) { | |
120fb9e4 RL |
491 | if (ui->meth->ui_write_string != NULL |
492 | && (ui->meth->ui_write_string(ui, | |
493 | sk_UI_STRING_value(ui->strings, i)) | |
494 | <= 0)) | |
0f113f3e | 495 | { |
0a687ab0 | 496 | state = "writing strings"; |
0f113f3e MC |
497 | ok = -1; |
498 | goto err; | |
499 | } | |
500 | } | |
501 | ||
120fb9e4 | 502 | if (ui->meth->ui_flush != NULL) |
0f113f3e MC |
503 | switch (ui->meth->ui_flush(ui)) { |
504 | case -1: /* Interrupt/Cancel/something... */ | |
f8922b51 | 505 | ui->flags &= ~UI_FLAG_REDOABLE; |
0f113f3e MC |
506 | ok = -2; |
507 | goto err; | |
508 | case 0: /* Errors */ | |
0a687ab0 | 509 | state = "flushing"; |
0f113f3e MC |
510 | ok = -1; |
511 | goto err; | |
512 | default: /* Success */ | |
513 | ok = 0; | |
514 | break; | |
515 | } | |
516 | ||
517 | for (i = 0; i < sk_UI_STRING_num(ui->strings); i++) { | |
120fb9e4 | 518 | if (ui->meth->ui_read_string != NULL) { |
0f113f3e MC |
519 | switch (ui->meth->ui_read_string(ui, |
520 | sk_UI_STRING_value(ui->strings, | |
521 | i))) { | |
522 | case -1: /* Interrupt/Cancel/something... */ | |
f8922b51 | 523 | ui->flags &= ~UI_FLAG_REDOABLE; |
0f113f3e MC |
524 | ok = -2; |
525 | goto err; | |
526 | case 0: /* Errors */ | |
0a687ab0 | 527 | state = "reading strings"; |
0f113f3e MC |
528 | ok = -1; |
529 | goto err; | |
530 | default: /* Success */ | |
531 | ok = 0; | |
532 | break; | |
533 | } | |
534 | } | |
535 | } | |
b96dba9e RL |
536 | |
537 | state = NULL; | |
0f113f3e | 538 | err: |
120fb9e4 | 539 | if (ui->meth->ui_close_session != NULL |
949320c5 | 540 | && ui->meth->ui_close_session(ui) <= 0) { |
0a687ab0 RL |
541 | if (state == NULL) |
542 | state = "closing session"; | |
543 | ok = -1; | |
544 | } | |
545 | ||
546 | if (ok == -1) { | |
547 | UIerr(UI_F_UI_PROCESS, UI_R_PROCESSING_ERROR); | |
548 | ERR_add_error_data(2, "while ", state); | |
549 | } | |
0f113f3e MC |
550 | return ok; |
551 | } | |
552 | ||
553 | int UI_ctrl(UI *ui, int cmd, long i, void *p, void (*f) (void)) | |
554 | { | |
555 | if (ui == NULL) { | |
556 | UIerr(UI_F_UI_CTRL, ERR_R_PASSED_NULL_PARAMETER); | |
557 | return -1; | |
558 | } | |
559 | switch (cmd) { | |
560 | case UI_CTRL_PRINT_ERRORS: | |
a63d5eaa | 561 | { |
0f113f3e MC |
562 | int save_flag = ! !(ui->flags & UI_FLAG_PRINT_ERRORS); |
563 | if (i) | |
564 | ui->flags |= UI_FLAG_PRINT_ERRORS; | |
565 | else | |
566 | ui->flags &= ~UI_FLAG_PRINT_ERRORS; | |
567 | return save_flag; | |
a63d5eaa | 568 | } |
0f113f3e MC |
569 | case UI_CTRL_IS_REDOABLE: |
570 | return ! !(ui->flags & UI_FLAG_REDOABLE); | |
571 | default: | |
572 | break; | |
573 | } | |
574 | UIerr(UI_F_UI_CTRL, UI_R_UNKNOWN_CONTROL_COMMAND); | |
575 | return -1; | |
576 | } | |
577 | ||
a63d5eaa | 578 | int UI_set_ex_data(UI *r, int idx, void *arg) |
0f113f3e | 579 | { |
26a7d938 | 580 | return CRYPTO_set_ex_data(&r->ex_data, idx, arg); |
0f113f3e | 581 | } |
a63d5eaa | 582 | |
8cc86b81 | 583 | void *UI_get_ex_data(const UI *r, int idx) |
0f113f3e | 584 | { |
26a7d938 | 585 | return CRYPTO_get_ex_data(&r->ex_data, idx); |
0f113f3e | 586 | } |
a63d5eaa | 587 | |
a63d5eaa | 588 | const UI_METHOD *UI_get_method(UI *ui) |
0f113f3e MC |
589 | { |
590 | return ui->meth; | |
591 | } | |
a63d5eaa RL |
592 | |
593 | const UI_METHOD *UI_set_method(UI *ui, const UI_METHOD *meth) | |
0f113f3e MC |
594 | { |
595 | ui->meth = meth; | |
596 | return ui->meth; | |
597 | } | |
a63d5eaa | 598 | |
472f727c | 599 | UI_METHOD *UI_create_method(const char *name) |
0f113f3e | 600 | { |
18cfc668 RL |
601 | UI_METHOD *ui_method = NULL; |
602 | ||
603 | if ((ui_method = OPENSSL_zalloc(sizeof(*ui_method))) == NULL | |
604 | || (ui_method->name = OPENSSL_strdup(name)) == NULL | |
605 | || !CRYPTO_new_ex_data(CRYPTO_EX_INDEX_UI_METHOD, ui_method, | |
606 | &ui_method->ex_data)) { | |
607 | if (ui_method) | |
608 | OPENSSL_free(ui_method->name); | |
609 | OPENSSL_free(ui_method); | |
610 | UIerr(UI_F_UI_CREATE_METHOD, ERR_R_MALLOC_FAILURE); | |
611 | return NULL; | |
6ef020c9 | 612 | } |
0f113f3e MC |
613 | return ui_method; |
614 | } | |
615 | ||
616 | /* | |
617 | * BIG FSCKING WARNING!!!! If you use this on a statically allocated method | |
618 | * (that is, it hasn't been allocated using UI_create_method(), you deserve | |
619 | * anything Murphy can throw at you and more! You have been warned. | |
620 | */ | |
eb929eef | 621 | void UI_destroy_method(UI_METHOD *ui_method) |
0f113f3e | 622 | { |
18cfc668 RL |
623 | if (ui_method == NULL) |
624 | return; | |
625 | CRYPTO_free_ex_data(CRYPTO_EX_INDEX_UI_METHOD, ui_method, | |
626 | &ui_method->ex_data); | |
0f113f3e MC |
627 | OPENSSL_free(ui_method->name); |
628 | ui_method->name = NULL; | |
629 | OPENSSL_free(ui_method); | |
630 | } | |
631 | ||
632 | int UI_method_set_opener(UI_METHOD *method, int (*opener) (UI *ui)) | |
633 | { | |
120fb9e4 | 634 | if (method != NULL) { |
0f113f3e MC |
635 | method->ui_open_session = opener; |
636 | return 0; | |
120fb9e4 RL |
637 | } |
638 | return -1; | |
0f113f3e MC |
639 | } |
640 | ||
641 | int UI_method_set_writer(UI_METHOD *method, | |
642 | int (*writer) (UI *ui, UI_STRING *uis)) | |
643 | { | |
120fb9e4 | 644 | if (method != NULL) { |
0f113f3e MC |
645 | method->ui_write_string = writer; |
646 | return 0; | |
120fb9e4 RL |
647 | } |
648 | return -1; | |
0f113f3e MC |
649 | } |
650 | ||
651 | int UI_method_set_flusher(UI_METHOD *method, int (*flusher) (UI *ui)) | |
652 | { | |
120fb9e4 | 653 | if (method != NULL) { |
0f113f3e MC |
654 | method->ui_flush = flusher; |
655 | return 0; | |
120fb9e4 RL |
656 | } |
657 | return -1; | |
0f113f3e MC |
658 | } |
659 | ||
660 | int UI_method_set_reader(UI_METHOD *method, | |
661 | int (*reader) (UI *ui, UI_STRING *uis)) | |
662 | { | |
120fb9e4 | 663 | if (method != NULL) { |
0f113f3e MC |
664 | method->ui_read_string = reader; |
665 | return 0; | |
120fb9e4 RL |
666 | } |
667 | return -1; | |
0f113f3e MC |
668 | } |
669 | ||
670 | int UI_method_set_closer(UI_METHOD *method, int (*closer) (UI *ui)) | |
671 | { | |
120fb9e4 | 672 | if (method != NULL) { |
0f113f3e MC |
673 | method->ui_close_session = closer; |
674 | return 0; | |
120fb9e4 RL |
675 | } |
676 | return -1; | |
0f113f3e MC |
677 | } |
678 | ||
545360c4 RL |
679 | int UI_method_set_data_duplicator(UI_METHOD *method, |
680 | void *(*duplicator) (UI *ui, void *ui_data), | |
681 | void (*destructor)(UI *ui, void *ui_data)) | |
682 | { | |
683 | if (method != NULL) { | |
684 | method->ui_duplicate_data = duplicator; | |
685 | method->ui_destroy_data = destructor; | |
686 | return 0; | |
687 | } | |
688 | return -1; | |
689 | } | |
690 | ||
0f113f3e MC |
691 | int UI_method_set_prompt_constructor(UI_METHOD *method, |
692 | char *(*prompt_constructor) (UI *ui, | |
693 | const char | |
694 | *object_desc, | |
695 | const char | |
696 | *object_name)) | |
697 | { | |
120fb9e4 | 698 | if (method != NULL) { |
0f113f3e MC |
699 | method->ui_construct_prompt = prompt_constructor; |
700 | return 0; | |
120fb9e4 RL |
701 | } |
702 | return -1; | |
0f113f3e MC |
703 | } |
704 | ||
18cfc668 RL |
705 | int UI_method_set_ex_data(UI_METHOD *method, int idx, void *data) |
706 | { | |
707 | return CRYPTO_set_ex_data(&method->ex_data, idx, data); | |
708 | } | |
709 | ||
a223ffe6 | 710 | int (*UI_method_get_opener(const UI_METHOD *method)) (UI *) |
120fb9e4 RL |
711 | { |
712 | if (method != NULL) | |
0f113f3e | 713 | return method->ui_open_session; |
120fb9e4 | 714 | return NULL; |
0f113f3e MC |
715 | } |
716 | ||
a223ffe6 | 717 | int (*UI_method_get_writer(const UI_METHOD *method)) (UI *, UI_STRING *) |
120fb9e4 RL |
718 | { |
719 | if (method != NULL) | |
0f113f3e | 720 | return method->ui_write_string; |
120fb9e4 | 721 | return NULL; |
0f113f3e MC |
722 | } |
723 | ||
a223ffe6 | 724 | int (*UI_method_get_flusher(const UI_METHOD *method)) (UI *) |
120fb9e4 RL |
725 | { |
726 | if (method != NULL) | |
0f113f3e | 727 | return method->ui_flush; |
120fb9e4 | 728 | return NULL; |
0f113f3e MC |
729 | } |
730 | ||
a223ffe6 | 731 | int (*UI_method_get_reader(const UI_METHOD *method)) (UI *, UI_STRING *) |
120fb9e4 RL |
732 | { |
733 | if (method != NULL) | |
0f113f3e | 734 | return method->ui_read_string; |
120fb9e4 | 735 | return NULL; |
0f113f3e MC |
736 | } |
737 | ||
a223ffe6 | 738 | int (*UI_method_get_closer(const UI_METHOD *method)) (UI *) |
120fb9e4 RL |
739 | { |
740 | if (method != NULL) | |
0f113f3e | 741 | return method->ui_close_session; |
120fb9e4 | 742 | return NULL; |
0f113f3e MC |
743 | } |
744 | ||
a223ffe6 RL |
745 | char *(*UI_method_get_prompt_constructor(const UI_METHOD *method)) |
746 | (UI *, const char *, const char *) | |
120fb9e4 RL |
747 | { |
748 | if (method != NULL) | |
0f113f3e | 749 | return method->ui_construct_prompt; |
120fb9e4 | 750 | return NULL; |
0f113f3e | 751 | } |
a63d5eaa | 752 | |
545360c4 RL |
753 | void *(*UI_method_get_data_duplicator(const UI_METHOD *method)) (UI *, void *) |
754 | { | |
755 | if (method != NULL) | |
756 | return method->ui_duplicate_data; | |
757 | return NULL; | |
758 | } | |
759 | ||
760 | void (*UI_method_get_data_destructor(const UI_METHOD *method)) (UI *, void *) | |
761 | { | |
762 | if (method != NULL) | |
763 | return method->ui_destroy_data; | |
764 | return NULL; | |
765 | } | |
766 | ||
18cfc668 RL |
767 | const void *UI_method_get_ex_data(const UI_METHOD *method, int idx) |
768 | { | |
769 | return CRYPTO_get_ex_data(&method->ex_data, idx); | |
770 | } | |
771 | ||
a63d5eaa | 772 | enum UI_string_types UI_get_string_type(UI_STRING *uis) |
0f113f3e | 773 | { |
0f113f3e MC |
774 | return uis->type; |
775 | } | |
a63d5eaa | 776 | |
9ad0f681 | 777 | int UI_get_input_flags(UI_STRING *uis) |
0f113f3e | 778 | { |
0f113f3e MC |
779 | return uis->input_flags; |
780 | } | |
9ad0f681 | 781 | |
a63d5eaa | 782 | const char *UI_get0_output_string(UI_STRING *uis) |
0f113f3e | 783 | { |
0f113f3e MC |
784 | return uis->out_string; |
785 | } | |
a63d5eaa | 786 | |
2d2ed9df | 787 | const char *UI_get0_action_string(UI_STRING *uis) |
0f113f3e | 788 | { |
0f113f3e | 789 | switch (uis->type) { |
0f113f3e MC |
790 | case UIT_BOOLEAN: |
791 | return uis->_.boolean_data.action_desc; | |
6e470e19 | 792 | case UIT_PROMPT: |
f3b3d7f0 RS |
793 | case UIT_NONE: |
794 | case UIT_VERIFY: | |
795 | case UIT_INFO: | |
796 | case UIT_ERROR: | |
797 | break; | |
0f113f3e | 798 | } |
f3b3d7f0 | 799 | return NULL; |
0f113f3e | 800 | } |
2d2ed9df | 801 | |
a63d5eaa | 802 | const char *UI_get0_result_string(UI_STRING *uis) |
0f113f3e | 803 | { |
0f113f3e MC |
804 | switch (uis->type) { |
805 | case UIT_PROMPT: | |
806 | case UIT_VERIFY: | |
807 | return uis->result_buf; | |
f3b3d7f0 RS |
808 | case UIT_NONE: |
809 | case UIT_BOOLEAN: | |
810 | case UIT_INFO: | |
811 | case UIT_ERROR: | |
812 | break; | |
0f113f3e | 813 | } |
f3b3d7f0 | 814 | return NULL; |
0f113f3e | 815 | } |
a63d5eaa | 816 | |
4e049e2c RL |
817 | int UI_get_result_string_length(UI_STRING *uis) |
818 | { | |
819 | switch (uis->type) { | |
820 | case UIT_PROMPT: | |
821 | case UIT_VERIFY: | |
822 | return uis->result_len; | |
823 | case UIT_NONE: | |
824 | case UIT_BOOLEAN: | |
825 | case UIT_INFO: | |
826 | case UIT_ERROR: | |
827 | break; | |
828 | } | |
829 | return -1; | |
830 | } | |
831 | ||
a63d5eaa | 832 | const char *UI_get0_test_string(UI_STRING *uis) |
0f113f3e | 833 | { |
0f113f3e MC |
834 | switch (uis->type) { |
835 | case UIT_VERIFY: | |
836 | return uis->_.string_data.test_buf; | |
f3b3d7f0 RS |
837 | case UIT_NONE: |
838 | case UIT_BOOLEAN: | |
839 | case UIT_INFO: | |
840 | case UIT_ERROR: | |
841 | case UIT_PROMPT: | |
842 | break; | |
0f113f3e | 843 | } |
f3b3d7f0 | 844 | return NULL; |
0f113f3e | 845 | } |
a63d5eaa RL |
846 | |
847 | int UI_get_result_minsize(UI_STRING *uis) | |
0f113f3e | 848 | { |
0f113f3e MC |
849 | switch (uis->type) { |
850 | case UIT_PROMPT: | |
851 | case UIT_VERIFY: | |
852 | return uis->_.string_data.result_minsize; | |
f3b3d7f0 RS |
853 | case UIT_NONE: |
854 | case UIT_INFO: | |
855 | case UIT_ERROR: | |
856 | case UIT_BOOLEAN: | |
857 | break; | |
0f113f3e | 858 | } |
f3b3d7f0 | 859 | return -1; |
0f113f3e | 860 | } |
a63d5eaa RL |
861 | |
862 | int UI_get_result_maxsize(UI_STRING *uis) | |
0f113f3e | 863 | { |
0f113f3e MC |
864 | switch (uis->type) { |
865 | case UIT_PROMPT: | |
866 | case UIT_VERIFY: | |
867 | return uis->_.string_data.result_maxsize; | |
f3b3d7f0 RS |
868 | case UIT_NONE: |
869 | case UIT_INFO: | |
870 | case UIT_ERROR: | |
871 | case UIT_BOOLEAN: | |
872 | break; | |
0f113f3e | 873 | } |
f3b3d7f0 | 874 | return -1; |
0f113f3e | 875 | } |
a63d5eaa | 876 | |
2d2ed9df | 877 | int UI_set_result(UI *ui, UI_STRING *uis, const char *result) |
0f113f3e | 878 | { |
4e049e2c RL |
879 | return UI_set_result_ex(ui, uis, result, strlen(result)); |
880 | } | |
0f113f3e | 881 | |
4e049e2c RL |
882 | int UI_set_result_ex(UI *ui, UI_STRING *uis, const char *result, int len) |
883 | { | |
0f113f3e MC |
884 | ui->flags &= ~UI_FLAG_REDOABLE; |
885 | ||
0f113f3e MC |
886 | switch (uis->type) { |
887 | case UIT_PROMPT: | |
888 | case UIT_VERIFY: | |
889 | { | |
890 | char number1[DECIMAL_SIZE(uis->_.string_data.result_minsize) + 1]; | |
891 | char number2[DECIMAL_SIZE(uis->_.string_data.result_maxsize) + 1]; | |
892 | ||
893 | BIO_snprintf(number1, sizeof(number1), "%d", | |
894 | uis->_.string_data.result_minsize); | |
895 | BIO_snprintf(number2, sizeof(number2), "%d", | |
896 | uis->_.string_data.result_maxsize); | |
897 | ||
4e049e2c | 898 | if (len < uis->_.string_data.result_minsize) { |
0f113f3e | 899 | ui->flags |= UI_FLAG_REDOABLE; |
4e049e2c | 900 | UIerr(UI_F_UI_SET_RESULT_EX, UI_R_RESULT_TOO_SMALL); |
0f113f3e MC |
901 | ERR_add_error_data(5, "You must type in ", |
902 | number1, " to ", number2, " characters"); | |
903 | return -1; | |
904 | } | |
4e049e2c | 905 | if (len > uis->_.string_data.result_maxsize) { |
0f113f3e | 906 | ui->flags |= UI_FLAG_REDOABLE; |
4e049e2c | 907 | UIerr(UI_F_UI_SET_RESULT_EX, UI_R_RESULT_TOO_LARGE); |
0f113f3e MC |
908 | ERR_add_error_data(5, "You must type in ", |
909 | number1, " to ", number2, " characters"); | |
910 | return -1; | |
911 | } | |
912 | } | |
913 | ||
bde588df | 914 | if (uis->result_buf == NULL) { |
4e049e2c | 915 | UIerr(UI_F_UI_SET_RESULT_EX, UI_R_NO_RESULT_BUFFER); |
0f113f3e MC |
916 | return -1; |
917 | } | |
918 | ||
4e049e2c RL |
919 | memcpy(uis->result_buf, result, len); |
920 | if (len <= uis->_.string_data.result_maxsize) | |
921 | uis->result_buf[len] = '\0'; | |
922 | uis->result_len = len; | |
0f113f3e MC |
923 | break; |
924 | case UIT_BOOLEAN: | |
925 | { | |
926 | const char *p; | |
927 | ||
bde588df | 928 | if (uis->result_buf == NULL) { |
4e049e2c | 929 | UIerr(UI_F_UI_SET_RESULT_EX, UI_R_NO_RESULT_BUFFER); |
0f113f3e MC |
930 | return -1; |
931 | } | |
932 | ||
933 | uis->result_buf[0] = '\0'; | |
934 | for (p = result; *p; p++) { | |
935 | if (strchr(uis->_.boolean_data.ok_chars, *p)) { | |
936 | uis->result_buf[0] = uis->_.boolean_data.ok_chars[0]; | |
937 | break; | |
938 | } | |
939 | if (strchr(uis->_.boolean_data.cancel_chars, *p)) { | |
940 | uis->result_buf[0] = uis->_.boolean_data.cancel_chars[0]; | |
941 | break; | |
942 | } | |
943 | } | |
944 | } | |
f3b3d7f0 RS |
945 | case UIT_NONE: |
946 | case UIT_INFO: | |
947 | case UIT_ERROR: | |
0f113f3e MC |
948 | break; |
949 | } | |
950 | return 0; | |
951 | } |