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