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