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