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