]>
Commit | Line | Data |
---|---|---|
0f113f3e | 1 | /* |
aa6bb135 | 2 | * Copyright 2001-2016 The OpenSSL Project Authors. All Rights Reserved. |
a63d5eaa | 3 | * |
aa6bb135 RS |
4 | * Licensed under the OpenSSL license (the "License"). You may not use |
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> | |
16 | #include "ui_locl.h" | |
17 | ||
a63d5eaa | 18 | UI *UI_new(void) |
0f113f3e MC |
19 | { |
20 | return (UI_new_method(NULL)); | |
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 | ||
b196e7d9 | 377 | prompt = OPENSSL_malloc(len + 1); |
0f113f3e MC |
378 | if (prompt == NULL) |
379 | return NULL; | |
7644a9ae RS |
380 | OPENSSL_strlcpy(prompt, prompt1, len + 1); |
381 | OPENSSL_strlcat(prompt, object_desc, len + 1); | |
120fb9e4 | 382 | if (object_name != NULL) { |
7644a9ae RS |
383 | OPENSSL_strlcat(prompt, prompt2, len + 1); |
384 | OPENSSL_strlcat(prompt, object_name, len + 1); | |
0f113f3e | 385 | } |
7644a9ae | 386 | OPENSSL_strlcat(prompt, prompt3, len + 1); |
0f113f3e MC |
387 | } |
388 | return prompt; | |
389 | } | |
a63d5eaa | 390 | |
1e7e62f8 | 391 | void *UI_add_user_data(UI *ui, void *user_data) |
0f113f3e MC |
392 | { |
393 | void *old_data = ui->user_data; | |
545360c4 RL |
394 | |
395 | if ((ui->flags & UI_FLAG_DUPL_DATA) != 0) { | |
396 | ui->meth->ui_destroy_data(ui, old_data); | |
397 | old_data = NULL; | |
398 | } | |
0f113f3e | 399 | ui->user_data = user_data; |
545360c4 | 400 | ui->flags &= ~UI_FLAG_DUPL_DATA; |
0f113f3e MC |
401 | return old_data; |
402 | } | |
1e7e62f8 | 403 | |
545360c4 RL |
404 | int UI_dup_user_data(UI *ui, void *user_data) |
405 | { | |
406 | void *duplicate = NULL; | |
407 | ||
408 | if (ui->meth->ui_duplicate_data == NULL | |
409 | || ui->meth->ui_destroy_data == NULL) { | |
410 | UIerr(UI_F_UI_DUP_USER_DATA, UI_R_USER_DATA_DUPLICATION_UNSUPPORTED); | |
411 | return -1; | |
412 | } | |
413 | ||
414 | duplicate = ui->meth->ui_duplicate_data(ui, user_data); | |
415 | if (duplicate == NULL) { | |
416 | UIerr(UI_F_UI_DUP_USER_DATA, ERR_R_MALLOC_FAILURE); | |
417 | return -1; | |
418 | } | |
419 | ||
420 | (void)UI_add_user_data(ui, duplicate); | |
421 | ui->flags |= UI_FLAG_DUPL_DATA; | |
422 | ||
423 | return 0; | |
424 | } | |
425 | ||
1e7e62f8 | 426 | void *UI_get0_user_data(UI *ui) |
0f113f3e MC |
427 | { |
428 | return ui->user_data; | |
429 | } | |
1e7e62f8 | 430 | |
a63d5eaa | 431 | const char *UI_get0_result(UI *ui, int i) |
0f113f3e MC |
432 | { |
433 | if (i < 0) { | |
434 | UIerr(UI_F_UI_GET0_RESULT, UI_R_INDEX_TOO_SMALL); | |
435 | return NULL; | |
436 | } | |
437 | if (i >= sk_UI_STRING_num(ui->strings)) { | |
438 | UIerr(UI_F_UI_GET0_RESULT, UI_R_INDEX_TOO_LARGE); | |
439 | return NULL; | |
440 | } | |
441 | return UI_get0_result_string(sk_UI_STRING_value(ui->strings, i)); | |
442 | } | |
a63d5eaa | 443 | |
2d2ed9df | 444 | static int print_error(const char *str, size_t len, UI *ui) |
0f113f3e MC |
445 | { |
446 | UI_STRING uis; | |
2d2ed9df | 447 | |
0f113f3e MC |
448 | memset(&uis, 0, sizeof(uis)); |
449 | uis.type = UIT_ERROR; | |
450 | uis.out_string = str; | |
2d2ed9df | 451 | |
120fb9e4 RL |
452 | if (ui->meth->ui_write_string != NULL |
453 | && ui->meth->ui_write_string(ui, &uis) <= 0) | |
0f113f3e MC |
454 | return -1; |
455 | return 0; | |
456 | } | |
2d2ed9df | 457 | |
a63d5eaa | 458 | int UI_process(UI *ui) |
0f113f3e MC |
459 | { |
460 | int i, ok = 0; | |
0a687ab0 | 461 | const char *state = "processing"; |
2d2ed9df | 462 | |
120fb9e4 RL |
463 | if (ui->meth->ui_open_session != NULL |
464 | && ui->meth->ui_open_session(ui) <= 0) { | |
0a687ab0 RL |
465 | state = "opening session"; |
466 | ok = -1; | |
467 | goto err; | |
468 | } | |
0f113f3e MC |
469 | |
470 | if (ui->flags & UI_FLAG_PRINT_ERRORS) | |
471 | ERR_print_errors_cb((int (*)(const char *, size_t, void *)) | |
472 | print_error, (void *)ui); | |
473 | ||
474 | for (i = 0; i < sk_UI_STRING_num(ui->strings); i++) { | |
120fb9e4 RL |
475 | if (ui->meth->ui_write_string != NULL |
476 | && (ui->meth->ui_write_string(ui, | |
477 | sk_UI_STRING_value(ui->strings, i)) | |
478 | <= 0)) | |
0f113f3e | 479 | { |
0a687ab0 | 480 | state = "writing strings"; |
0f113f3e MC |
481 | ok = -1; |
482 | goto err; | |
483 | } | |
484 | } | |
485 | ||
120fb9e4 | 486 | if (ui->meth->ui_flush != NULL) |
0f113f3e MC |
487 | switch (ui->meth->ui_flush(ui)) { |
488 | case -1: /* Interrupt/Cancel/something... */ | |
489 | ok = -2; | |
490 | goto err; | |
491 | case 0: /* Errors */ | |
0a687ab0 | 492 | state = "flushing"; |
0f113f3e MC |
493 | ok = -1; |
494 | goto err; | |
495 | default: /* Success */ | |
496 | ok = 0; | |
497 | break; | |
498 | } | |
499 | ||
500 | for (i = 0; i < sk_UI_STRING_num(ui->strings); i++) { | |
120fb9e4 | 501 | if (ui->meth->ui_read_string != NULL) { |
0f113f3e MC |
502 | switch (ui->meth->ui_read_string(ui, |
503 | sk_UI_STRING_value(ui->strings, | |
504 | i))) { | |
505 | case -1: /* Interrupt/Cancel/something... */ | |
506 | ok = -2; | |
507 | goto err; | |
508 | case 0: /* Errors */ | |
0a687ab0 | 509 | state = "reading strings"; |
0f113f3e MC |
510 | ok = -1; |
511 | goto err; | |
512 | default: /* Success */ | |
513 | ok = 0; | |
514 | break; | |
515 | } | |
516 | } | |
517 | } | |
518 | err: | |
120fb9e4 | 519 | if (ui->meth->ui_close_session != NULL |
949320c5 | 520 | && ui->meth->ui_close_session(ui) <= 0) { |
0a687ab0 RL |
521 | if (state == NULL) |
522 | state = "closing session"; | |
523 | ok = -1; | |
524 | } | |
525 | ||
526 | if (ok == -1) { | |
527 | UIerr(UI_F_UI_PROCESS, UI_R_PROCESSING_ERROR); | |
528 | ERR_add_error_data(2, "while ", state); | |
529 | } | |
0f113f3e MC |
530 | return ok; |
531 | } | |
532 | ||
533 | int UI_ctrl(UI *ui, int cmd, long i, void *p, void (*f) (void)) | |
534 | { | |
535 | if (ui == NULL) { | |
536 | UIerr(UI_F_UI_CTRL, ERR_R_PASSED_NULL_PARAMETER); | |
537 | return -1; | |
538 | } | |
539 | switch (cmd) { | |
540 | case UI_CTRL_PRINT_ERRORS: | |
a63d5eaa | 541 | { |
0f113f3e MC |
542 | int save_flag = ! !(ui->flags & UI_FLAG_PRINT_ERRORS); |
543 | if (i) | |
544 | ui->flags |= UI_FLAG_PRINT_ERRORS; | |
545 | else | |
546 | ui->flags &= ~UI_FLAG_PRINT_ERRORS; | |
547 | return save_flag; | |
a63d5eaa | 548 | } |
0f113f3e MC |
549 | case UI_CTRL_IS_REDOABLE: |
550 | return ! !(ui->flags & UI_FLAG_REDOABLE); | |
551 | default: | |
552 | break; | |
553 | } | |
554 | UIerr(UI_F_UI_CTRL, UI_R_UNKNOWN_CONTROL_COMMAND); | |
555 | return -1; | |
556 | } | |
557 | ||
a63d5eaa | 558 | int UI_set_ex_data(UI *r, int idx, void *arg) |
0f113f3e MC |
559 | { |
560 | return (CRYPTO_set_ex_data(&r->ex_data, idx, arg)); | |
561 | } | |
a63d5eaa RL |
562 | |
563 | void *UI_get_ex_data(UI *r, int idx) | |
0f113f3e MC |
564 | { |
565 | return (CRYPTO_get_ex_data(&r->ex_data, idx)); | |
566 | } | |
a63d5eaa | 567 | |
a63d5eaa | 568 | const UI_METHOD *UI_get_method(UI *ui) |
0f113f3e MC |
569 | { |
570 | return ui->meth; | |
571 | } | |
a63d5eaa RL |
572 | |
573 | const UI_METHOD *UI_set_method(UI *ui, const UI_METHOD *meth) | |
0f113f3e MC |
574 | { |
575 | ui->meth = meth; | |
576 | return ui->meth; | |
577 | } | |
a63d5eaa | 578 | |
472f727c | 579 | UI_METHOD *UI_create_method(const char *name) |
0f113f3e | 580 | { |
18cfc668 RL |
581 | UI_METHOD *ui_method = NULL; |
582 | ||
583 | if ((ui_method = OPENSSL_zalloc(sizeof(*ui_method))) == NULL | |
584 | || (ui_method->name = OPENSSL_strdup(name)) == NULL | |
585 | || !CRYPTO_new_ex_data(CRYPTO_EX_INDEX_UI_METHOD, ui_method, | |
586 | &ui_method->ex_data)) { | |
587 | if (ui_method) | |
588 | OPENSSL_free(ui_method->name); | |
589 | OPENSSL_free(ui_method); | |
590 | UIerr(UI_F_UI_CREATE_METHOD, ERR_R_MALLOC_FAILURE); | |
591 | return NULL; | |
6ef020c9 | 592 | } |
0f113f3e MC |
593 | return ui_method; |
594 | } | |
595 | ||
596 | /* | |
597 | * BIG FSCKING WARNING!!!! If you use this on a statically allocated method | |
598 | * (that is, it hasn't been allocated using UI_create_method(), you deserve | |
599 | * anything Murphy can throw at you and more! You have been warned. | |
600 | */ | |
eb929eef | 601 | void UI_destroy_method(UI_METHOD *ui_method) |
0f113f3e | 602 | { |
18cfc668 RL |
603 | if (ui_method == NULL) |
604 | return; | |
605 | CRYPTO_free_ex_data(CRYPTO_EX_INDEX_UI_METHOD, ui_method, | |
606 | &ui_method->ex_data); | |
0f113f3e MC |
607 | OPENSSL_free(ui_method->name); |
608 | ui_method->name = NULL; | |
609 | OPENSSL_free(ui_method); | |
610 | } | |
611 | ||
612 | int UI_method_set_opener(UI_METHOD *method, int (*opener) (UI *ui)) | |
613 | { | |
120fb9e4 | 614 | if (method != NULL) { |
0f113f3e MC |
615 | method->ui_open_session = opener; |
616 | return 0; | |
120fb9e4 RL |
617 | } |
618 | return -1; | |
0f113f3e MC |
619 | } |
620 | ||
621 | int UI_method_set_writer(UI_METHOD *method, | |
622 | int (*writer) (UI *ui, UI_STRING *uis)) | |
623 | { | |
120fb9e4 | 624 | if (method != NULL) { |
0f113f3e MC |
625 | method->ui_write_string = writer; |
626 | return 0; | |
120fb9e4 RL |
627 | } |
628 | return -1; | |
0f113f3e MC |
629 | } |
630 | ||
631 | int UI_method_set_flusher(UI_METHOD *method, int (*flusher) (UI *ui)) | |
632 | { | |
120fb9e4 | 633 | if (method != NULL) { |
0f113f3e MC |
634 | method->ui_flush = flusher; |
635 | return 0; | |
120fb9e4 RL |
636 | } |
637 | return -1; | |
0f113f3e MC |
638 | } |
639 | ||
640 | int UI_method_set_reader(UI_METHOD *method, | |
641 | int (*reader) (UI *ui, UI_STRING *uis)) | |
642 | { | |
120fb9e4 | 643 | if (method != NULL) { |
0f113f3e MC |
644 | method->ui_read_string = reader; |
645 | return 0; | |
120fb9e4 RL |
646 | } |
647 | return -1; | |
0f113f3e MC |
648 | } |
649 | ||
650 | int UI_method_set_closer(UI_METHOD *method, int (*closer) (UI *ui)) | |
651 | { | |
120fb9e4 | 652 | if (method != NULL) { |
0f113f3e MC |
653 | method->ui_close_session = closer; |
654 | return 0; | |
120fb9e4 RL |
655 | } |
656 | return -1; | |
0f113f3e MC |
657 | } |
658 | ||
545360c4 RL |
659 | int UI_method_set_data_duplicator(UI_METHOD *method, |
660 | void *(*duplicator) (UI *ui, void *ui_data), | |
661 | void (*destructor)(UI *ui, void *ui_data)) | |
662 | { | |
663 | if (method != NULL) { | |
664 | method->ui_duplicate_data = duplicator; | |
665 | method->ui_destroy_data = destructor; | |
666 | return 0; | |
667 | } | |
668 | return -1; | |
669 | } | |
670 | ||
0f113f3e MC |
671 | int UI_method_set_prompt_constructor(UI_METHOD *method, |
672 | char *(*prompt_constructor) (UI *ui, | |
673 | const char | |
674 | *object_desc, | |
675 | const char | |
676 | *object_name)) | |
677 | { | |
120fb9e4 | 678 | if (method != NULL) { |
0f113f3e MC |
679 | method->ui_construct_prompt = prompt_constructor; |
680 | return 0; | |
120fb9e4 RL |
681 | } |
682 | return -1; | |
0f113f3e MC |
683 | } |
684 | ||
18cfc668 RL |
685 | int UI_method_set_ex_data(UI_METHOD *method, int idx, void *data) |
686 | { | |
687 | return CRYPTO_set_ex_data(&method->ex_data, idx, data); | |
688 | } | |
689 | ||
a223ffe6 | 690 | int (*UI_method_get_opener(const UI_METHOD *method)) (UI *) |
120fb9e4 RL |
691 | { |
692 | if (method != NULL) | |
0f113f3e | 693 | return method->ui_open_session; |
120fb9e4 | 694 | return NULL; |
0f113f3e MC |
695 | } |
696 | ||
a223ffe6 | 697 | int (*UI_method_get_writer(const UI_METHOD *method)) (UI *, UI_STRING *) |
120fb9e4 RL |
698 | { |
699 | if (method != NULL) | |
0f113f3e | 700 | return method->ui_write_string; |
120fb9e4 | 701 | return NULL; |
0f113f3e MC |
702 | } |
703 | ||
a223ffe6 | 704 | int (*UI_method_get_flusher(const UI_METHOD *method)) (UI *) |
120fb9e4 RL |
705 | { |
706 | if (method != NULL) | |
0f113f3e | 707 | return method->ui_flush; |
120fb9e4 | 708 | return NULL; |
0f113f3e MC |
709 | } |
710 | ||
a223ffe6 | 711 | int (*UI_method_get_reader(const UI_METHOD *method)) (UI *, UI_STRING *) |
120fb9e4 RL |
712 | { |
713 | if (method != NULL) | |
0f113f3e | 714 | return method->ui_read_string; |
120fb9e4 | 715 | return NULL; |
0f113f3e MC |
716 | } |
717 | ||
a223ffe6 | 718 | int (*UI_method_get_closer(const UI_METHOD *method)) (UI *) |
120fb9e4 RL |
719 | { |
720 | if (method != NULL) | |
0f113f3e | 721 | return method->ui_close_session; |
120fb9e4 | 722 | return NULL; |
0f113f3e MC |
723 | } |
724 | ||
a223ffe6 RL |
725 | char *(*UI_method_get_prompt_constructor(const UI_METHOD *method)) |
726 | (UI *, const char *, const char *) | |
120fb9e4 RL |
727 | { |
728 | if (method != NULL) | |
0f113f3e | 729 | return method->ui_construct_prompt; |
120fb9e4 | 730 | return NULL; |
0f113f3e | 731 | } |
a63d5eaa | 732 | |
545360c4 RL |
733 | void *(*UI_method_get_data_duplicator(const UI_METHOD *method)) (UI *, void *) |
734 | { | |
735 | if (method != NULL) | |
736 | return method->ui_duplicate_data; | |
737 | return NULL; | |
738 | } | |
739 | ||
740 | void (*UI_method_get_data_destructor(const UI_METHOD *method)) (UI *, void *) | |
741 | { | |
742 | if (method != NULL) | |
743 | return method->ui_destroy_data; | |
744 | return NULL; | |
745 | } | |
746 | ||
18cfc668 RL |
747 | const void *UI_method_get_ex_data(const UI_METHOD *method, int idx) |
748 | { | |
749 | return CRYPTO_get_ex_data(&method->ex_data, idx); | |
750 | } | |
751 | ||
a63d5eaa | 752 | enum UI_string_types UI_get_string_type(UI_STRING *uis) |
0f113f3e | 753 | { |
0f113f3e MC |
754 | return uis->type; |
755 | } | |
a63d5eaa | 756 | |
9ad0f681 | 757 | int UI_get_input_flags(UI_STRING *uis) |
0f113f3e | 758 | { |
0f113f3e MC |
759 | return uis->input_flags; |
760 | } | |
9ad0f681 | 761 | |
a63d5eaa | 762 | const char *UI_get0_output_string(UI_STRING *uis) |
0f113f3e | 763 | { |
0f113f3e MC |
764 | return uis->out_string; |
765 | } | |
a63d5eaa | 766 | |
2d2ed9df | 767 | const char *UI_get0_action_string(UI_STRING *uis) |
0f113f3e | 768 | { |
0f113f3e | 769 | switch (uis->type) { |
0f113f3e MC |
770 | case UIT_BOOLEAN: |
771 | return uis->_.boolean_data.action_desc; | |
6e470e19 | 772 | case UIT_PROMPT: |
f3b3d7f0 RS |
773 | case UIT_NONE: |
774 | case UIT_VERIFY: | |
775 | case UIT_INFO: | |
776 | case UIT_ERROR: | |
777 | break; | |
0f113f3e | 778 | } |
f3b3d7f0 | 779 | return NULL; |
0f113f3e | 780 | } |
2d2ed9df | 781 | |
a63d5eaa | 782 | const char *UI_get0_result_string(UI_STRING *uis) |
0f113f3e | 783 | { |
0f113f3e MC |
784 | switch (uis->type) { |
785 | case UIT_PROMPT: | |
786 | case UIT_VERIFY: | |
787 | return uis->result_buf; | |
f3b3d7f0 RS |
788 | case UIT_NONE: |
789 | case UIT_BOOLEAN: | |
790 | case UIT_INFO: | |
791 | case UIT_ERROR: | |
792 | break; | |
0f113f3e | 793 | } |
f3b3d7f0 | 794 | return NULL; |
0f113f3e | 795 | } |
a63d5eaa RL |
796 | |
797 | const char *UI_get0_test_string(UI_STRING *uis) | |
0f113f3e | 798 | { |
0f113f3e MC |
799 | switch (uis->type) { |
800 | case UIT_VERIFY: | |
801 | return uis->_.string_data.test_buf; | |
f3b3d7f0 RS |
802 | case UIT_NONE: |
803 | case UIT_BOOLEAN: | |
804 | case UIT_INFO: | |
805 | case UIT_ERROR: | |
806 | case UIT_PROMPT: | |
807 | break; | |
0f113f3e | 808 | } |
f3b3d7f0 | 809 | return NULL; |
0f113f3e | 810 | } |
a63d5eaa RL |
811 | |
812 | int UI_get_result_minsize(UI_STRING *uis) | |
0f113f3e | 813 | { |
0f113f3e MC |
814 | switch (uis->type) { |
815 | case UIT_PROMPT: | |
816 | case UIT_VERIFY: | |
817 | return uis->_.string_data.result_minsize; | |
f3b3d7f0 RS |
818 | case UIT_NONE: |
819 | case UIT_INFO: | |
820 | case UIT_ERROR: | |
821 | case UIT_BOOLEAN: | |
822 | break; | |
0f113f3e | 823 | } |
f3b3d7f0 | 824 | return -1; |
0f113f3e | 825 | } |
a63d5eaa RL |
826 | |
827 | int UI_get_result_maxsize(UI_STRING *uis) | |
0f113f3e | 828 | { |
0f113f3e MC |
829 | switch (uis->type) { |
830 | case UIT_PROMPT: | |
831 | case UIT_VERIFY: | |
832 | return uis->_.string_data.result_maxsize; | |
f3b3d7f0 RS |
833 | case UIT_NONE: |
834 | case UIT_INFO: | |
835 | case UIT_ERROR: | |
836 | case UIT_BOOLEAN: | |
837 | break; | |
0f113f3e | 838 | } |
f3b3d7f0 | 839 | return -1; |
0f113f3e | 840 | } |
a63d5eaa | 841 | |
2d2ed9df | 842 | int UI_set_result(UI *ui, UI_STRING *uis, const char *result) |
0f113f3e MC |
843 | { |
844 | int l = strlen(result); | |
845 | ||
846 | ui->flags &= ~UI_FLAG_REDOABLE; | |
847 | ||
0f113f3e MC |
848 | switch (uis->type) { |
849 | case UIT_PROMPT: | |
850 | case UIT_VERIFY: | |
851 | { | |
852 | char number1[DECIMAL_SIZE(uis->_.string_data.result_minsize) + 1]; | |
853 | char number2[DECIMAL_SIZE(uis->_.string_data.result_maxsize) + 1]; | |
854 | ||
855 | BIO_snprintf(number1, sizeof(number1), "%d", | |
856 | uis->_.string_data.result_minsize); | |
857 | BIO_snprintf(number2, sizeof(number2), "%d", | |
858 | uis->_.string_data.result_maxsize); | |
859 | ||
860 | if (l < uis->_.string_data.result_minsize) { | |
861 | ui->flags |= UI_FLAG_REDOABLE; | |
862 | UIerr(UI_F_UI_SET_RESULT, UI_R_RESULT_TOO_SMALL); | |
863 | ERR_add_error_data(5, "You must type in ", | |
864 | number1, " to ", number2, " characters"); | |
865 | return -1; | |
866 | } | |
867 | if (l > uis->_.string_data.result_maxsize) { | |
868 | ui->flags |= UI_FLAG_REDOABLE; | |
869 | UIerr(UI_F_UI_SET_RESULT, UI_R_RESULT_TOO_LARGE); | |
870 | ERR_add_error_data(5, "You must type in ", | |
871 | number1, " to ", number2, " characters"); | |
872 | return -1; | |
873 | } | |
874 | } | |
875 | ||
bde588df | 876 | if (uis->result_buf == NULL) { |
0f113f3e MC |
877 | UIerr(UI_F_UI_SET_RESULT, UI_R_NO_RESULT_BUFFER); |
878 | return -1; | |
879 | } | |
880 | ||
7644a9ae | 881 | OPENSSL_strlcpy(uis->result_buf, result, |
0f113f3e MC |
882 | uis->_.string_data.result_maxsize + 1); |
883 | break; | |
884 | case UIT_BOOLEAN: | |
885 | { | |
886 | const char *p; | |
887 | ||
bde588df | 888 | if (uis->result_buf == NULL) { |
0f113f3e MC |
889 | UIerr(UI_F_UI_SET_RESULT, UI_R_NO_RESULT_BUFFER); |
890 | return -1; | |
891 | } | |
892 | ||
893 | uis->result_buf[0] = '\0'; | |
894 | for (p = result; *p; p++) { | |
895 | if (strchr(uis->_.boolean_data.ok_chars, *p)) { | |
896 | uis->result_buf[0] = uis->_.boolean_data.ok_chars[0]; | |
897 | break; | |
898 | } | |
899 | if (strchr(uis->_.boolean_data.cancel_chars, *p)) { | |
900 | uis->result_buf[0] = uis->_.boolean_data.cancel_chars[0]; | |
901 | break; | |
902 | } | |
903 | } | |
904 | } | |
f3b3d7f0 RS |
905 | case UIT_NONE: |
906 | case UIT_INFO: | |
907 | case UIT_ERROR: | |
0f113f3e MC |
908 | break; |
909 | } | |
910 | return 0; | |
911 | } |