xref: /freebsd/crypto/openssl/crypto/ui/ui_lib.c (revision b077aed33b7b6aefca7b17ddb250cf521f938613)
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  
211      if (prompt != NULL) {
212          prompt_copy = OPENSSL_strdup(prompt);
213          if (prompt_copy == NULL) {
214              ERR_raise(ERR_LIB_UI, ERR_R_MALLOC_FAILURE);
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  }
223  
UI_add_verify_string(UI * ui,const char * prompt,int flags,char * result_buf,int minsize,int maxsize,const char * test_buf)224  int UI_add_verify_string(UI *ui, const char *prompt, int flags,
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  }
232  
UI_dup_verify_string(UI * ui,const char * prompt,int flags,char * result_buf,int minsize,int maxsize,const char * test_buf)233  int UI_dup_verify_string(UI *ui, const char *prompt, int flags,
234                           char *result_buf, int minsize, int maxsize,
235                           const char *test_buf)
236  {
237      char *prompt_copy = NULL;
238  
239      if (prompt != NULL) {
240          prompt_copy = OPENSSL_strdup(prompt);
241          if (prompt_copy == NULL) {
242              ERR_raise(ERR_LIB_UI, ERR_R_MALLOC_FAILURE);
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  }
251  
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)252  int UI_add_input_boolean(UI *ui, const char *prompt, const char *action_desc,
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  }
260  
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)261  int UI_dup_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      char *prompt_copy = NULL;
266      char *action_desc_copy = NULL;
267      char *ok_chars_copy = NULL;
268      char *cancel_chars_copy = NULL;
269  
270      if (prompt != NULL) {
271          prompt_copy = OPENSSL_strdup(prompt);
272          if (prompt_copy == NULL) {
273              ERR_raise(ERR_LIB_UI, ERR_R_MALLOC_FAILURE);
274              goto err;
275          }
276      }
277  
278      if (action_desc != NULL) {
279          action_desc_copy = OPENSSL_strdup(action_desc);
280          if (action_desc_copy == NULL) {
281              ERR_raise(ERR_LIB_UI, ERR_R_MALLOC_FAILURE);
282              goto err;
283          }
284      }
285  
286      if (ok_chars != NULL) {
287          ok_chars_copy = OPENSSL_strdup(ok_chars);
288          if (ok_chars_copy == NULL) {
289              ERR_raise(ERR_LIB_UI, ERR_R_MALLOC_FAILURE);
290              goto err;
291          }
292      }
293  
294      if (cancel_chars != NULL) {
295          cancel_chars_copy = OPENSSL_strdup(cancel_chars);
296          if (cancel_chars_copy == NULL) {
297              ERR_raise(ERR_LIB_UI, ERR_R_MALLOC_FAILURE);
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);
305   err:
306      OPENSSL_free(prompt_copy);
307      OPENSSL_free(action_desc_copy);
308      OPENSSL_free(ok_chars_copy);
309      OPENSSL_free(cancel_chars_copy);
310      return -1;
311  }
312  
UI_add_info_string(UI * ui,const char * text)313  int UI_add_info_string(UI *ui, const char *text)
314  {
315      return general_allocate_string(ui, text, 0, UIT_INFO, 0, NULL, 0, 0,
316                                     NULL);
317  }
318  
UI_dup_info_string(UI * ui,const char * text)319  int UI_dup_info_string(UI *ui, const char *text)
320  {
321      char *text_copy = NULL;
322  
323      if (text != NULL) {
324          text_copy = OPENSSL_strdup(text);
325          if (text_copy == NULL) {
326              ERR_raise(ERR_LIB_UI, ERR_R_MALLOC_FAILURE);
327              return -1;
328          }
329      }
330  
331      return general_allocate_string(ui, text_copy, 1, UIT_INFO, 0, NULL,
332                                     0, 0, NULL);
333  }
334  
UI_add_error_string(UI * ui,const char * text)335  int UI_add_error_string(UI *ui, const char *text)
336  {
337      return general_allocate_string(ui, text, 0, UIT_ERROR, 0, NULL, 0, 0,
338                                     NULL);
339  }
340  
UI_dup_error_string(UI * ui,const char * text)341  int UI_dup_error_string(UI *ui, const char *text)
342  {
343      char *text_copy = NULL;
344  
345      if (text != NULL) {
346          text_copy = OPENSSL_strdup(text);
347          if (text_copy == NULL) {
348              ERR_raise(ERR_LIB_UI, ERR_R_MALLOC_FAILURE);
349              return -1;
350          }
351      }
352      return general_allocate_string(ui, text_copy, 1, UIT_ERROR, 0, NULL,
353                                     0, 0, NULL);
354  }
355  
UI_construct_prompt(UI * ui,const char * phrase_desc,const char * object_name)356  char *UI_construct_prompt(UI *ui, const char *phrase_desc,
357                            const char *object_name)
358  {
359      char *prompt = NULL;
360  
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);
363      else {
364          char prompt1[] = "Enter ";
365          char prompt2[] = " for ";
366          char prompt3[] = ":";
367          int len = 0;
368  
369          if (phrase_desc == NULL)
370              return NULL;
371          len = sizeof(prompt1) - 1 + strlen(phrase_desc);
372          if (object_name != NULL)
373              len += sizeof(prompt2) - 1 + strlen(object_name);
374          len += sizeof(prompt3) - 1;
375  
376          if ((prompt = OPENSSL_malloc(len + 1)) == NULL) {
377              ERR_raise(ERR_LIB_UI, ERR_R_MALLOC_FAILURE);
378              return NULL;
379          }
380          OPENSSL_strlcpy(prompt, prompt1, len + 1);
381          OPENSSL_strlcat(prompt, phrase_desc, len + 1);
382          if (object_name != NULL) {
383              OPENSSL_strlcat(prompt, prompt2, len + 1);
384              OPENSSL_strlcat(prompt, object_name, len + 1);
385          }
386          OPENSSL_strlcat(prompt, prompt3, len + 1);
387      }
388      return prompt;
389  }
390  
UI_add_user_data(UI * ui,void * user_data)391  void *UI_add_user_data(UI *ui, void *user_data)
392  {
393      void *old_data = ui->user_data;
394  
395      if ((ui->flags & UI_FLAG_DUPL_DATA) != 0) {
396          ui->meth->ui_destroy_data(ui, old_data);
397          old_data = NULL;
398      }
399      ui->user_data = user_data;
400      ui->flags &= ~UI_FLAG_DUPL_DATA;
401      return old_data;
402  }
403  
UI_dup_user_data(UI * ui,void * user_data)404  int UI_dup_user_data(UI *ui, void *user_data)
405  {
406      void *duplicate = NULL;
407  
408      if (ui->meth->ui_duplicate_data == NULL
409          || ui->meth->ui_destroy_data == NULL) {
410          ERR_raise(ERR_LIB_UI, UI_R_USER_DATA_DUPLICATION_UNSUPPORTED);
411          return -1;
412      }
413  
414      duplicate = ui->meth->ui_duplicate_data(ui, user_data);
415      if (duplicate == NULL) {
416          ERR_raise(ERR_LIB_UI, ERR_R_MALLOC_FAILURE);
417          return -1;
418      }
419  
420      (void)UI_add_user_data(ui, duplicate);
421      ui->flags |= UI_FLAG_DUPL_DATA;
422  
423      return 0;
424  }
425  
UI_get0_user_data(UI * ui)426  void *UI_get0_user_data(UI *ui)
427  {
428      return ui->user_data;
429  }
430  
UI_get0_result(UI * ui,int i)431  const char *UI_get0_result(UI *ui, int i)
432  {
433      if (i < 0) {
434          ERR_raise(ERR_LIB_UI, UI_R_INDEX_TOO_SMALL);
435          return NULL;
436      }
437      if (i >= sk_UI_STRING_num(ui->strings)) {
438          ERR_raise(ERR_LIB_UI, UI_R_INDEX_TOO_LARGE);
439          return NULL;
440      }
441      return UI_get0_result_string(sk_UI_STRING_value(ui->strings, i));
442  }
443  
UI_get_result_length(UI * ui,int i)444  int UI_get_result_length(UI *ui, int i)
445  {
446      if (i < 0) {
447          ERR_raise(ERR_LIB_UI, UI_R_INDEX_TOO_SMALL);
448          return -1;
449      }
450      if (i >= sk_UI_STRING_num(ui->strings)) {
451          ERR_raise(ERR_LIB_UI, UI_R_INDEX_TOO_LARGE);
452          return -1;
453      }
454      return UI_get_result_string_length(sk_UI_STRING_value(ui->strings, i));
455  }
456  
print_error(const char * str,size_t len,UI * ui)457  static int print_error(const char *str, size_t len, UI *ui)
458  {
459      UI_STRING uis;
460  
461      memset(&uis, 0, sizeof(uis));
462      uis.type = UIT_ERROR;
463      uis.out_string = str;
464  
465      if (ui->meth->ui_write_string != NULL
466          && ui->meth->ui_write_string(ui, &uis) <= 0)
467          return -1;
468      return 0;
469  }
470  
UI_process(UI * ui)471  int UI_process(UI *ui)
472  {
473      int i, ok = 0;
474      const char *state = "processing";
475  
476      if (ui->meth->ui_open_session != NULL
477          && ui->meth->ui_open_session(ui) <= 0) {
478          state = "opening session";
479          ok = -1;
480          goto err;
481      }
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++) {
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))
492          {
493              state = "writing strings";
494              ok = -1;
495              goto err;
496          }
497      }
498  
499      if (ui->meth->ui_flush != NULL)
500          switch (ui->meth->ui_flush(ui)) {
501          case -1:               /* Interrupt/Cancel/something... */
502              ui->flags &= ~UI_FLAG_REDOABLE;
503              ok = -2;
504              goto err;
505          case 0:                /* Errors */
506              state = "flushing";
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++) {
515          if (ui->meth->ui_read_string != NULL) {
516              switch (ui->meth->ui_read_string(ui,
517                                               sk_UI_STRING_value(ui->strings,
518                                                                  i))) {
519              case -1:           /* Interrupt/Cancel/something... */
520                  ui->flags &= ~UI_FLAG_REDOABLE;
521                  ok = -2;
522                  goto err;
523              case 0:            /* Errors */
524                  state = "reading strings";
525                  ok = -1;
526                  goto err;
527              default:           /* Success */
528                  ok = 0;
529                  break;
530              }
531          } else {
532              ui->flags &= ~UI_FLAG_REDOABLE;
533              ok = -2;
534              goto err;
535          }
536      }
537  
538      state = NULL;
539   err:
540      if (ui->meth->ui_close_session != NULL
541          && ui->meth->ui_close_session(ui) <= 0) {
542          if (state == NULL)
543              state = "closing session";
544          ok = -1;
545      }
546  
547      if (ok == -1)
548          ERR_raise_data(ERR_LIB_UI, UI_R_PROCESSING_ERROR, "while %s", state);
549      return ok;
550  }
551  
UI_ctrl(UI * ui,int cmd,long i,void * p,void (* f)(void))552  int UI_ctrl(UI *ui, int cmd, long i, void *p, void (*f) (void))
553  {
554      if (ui == NULL) {
555          ERR_raise(ERR_LIB_UI, ERR_R_PASSED_NULL_PARAMETER);
556          return -1;
557      }
558      switch (cmd) {
559      case UI_CTRL_PRINT_ERRORS:
560          {
561              int save_flag = ! !(ui->flags & UI_FLAG_PRINT_ERRORS);
562              if (i)
563                  ui->flags |= UI_FLAG_PRINT_ERRORS;
564              else
565                  ui->flags &= ~UI_FLAG_PRINT_ERRORS;
566              return save_flag;
567          }
568      case UI_CTRL_IS_REDOABLE:
569          return ! !(ui->flags & UI_FLAG_REDOABLE);
570      default:
571          break;
572      }
573      ERR_raise(ERR_LIB_UI, UI_R_UNKNOWN_CONTROL_COMMAND);
574      return -1;
575  }
576  
UI_set_ex_data(UI * r,int idx,void * arg)577  int UI_set_ex_data(UI *r, int idx, void *arg)
578  {
579      return CRYPTO_set_ex_data(&r->ex_data, idx, arg);
580  }
581  
UI_get_ex_data(const UI * r,int idx)582  void *UI_get_ex_data(const UI *r, int idx)
583  {
584      return CRYPTO_get_ex_data(&r->ex_data, idx);
585  }
586  
UI_get_method(UI * ui)587  const UI_METHOD *UI_get_method(UI *ui)
588  {
589      return ui->meth;
590  }
591  
UI_set_method(UI * ui,const UI_METHOD * meth)592  const UI_METHOD *UI_set_method(UI *ui, const UI_METHOD *meth)
593  {
594      ui->meth = meth;
595      return ui->meth;
596  }
597  
UI_create_method(const char * name)598  UI_METHOD *UI_create_method(const char *name)
599  {
600      UI_METHOD *ui_method = NULL;
601  
602      if ((ui_method = OPENSSL_zalloc(sizeof(*ui_method))) == NULL
603          || (ui_method->name = OPENSSL_strdup(name)) == NULL
604          || !CRYPTO_new_ex_data(CRYPTO_EX_INDEX_UI_METHOD, ui_method,
605                                 &ui_method->ex_data)) {
606          if (ui_method)
607              OPENSSL_free(ui_method->name);
608          OPENSSL_free(ui_method);
609          ERR_raise(ERR_LIB_UI, ERR_R_MALLOC_FAILURE);
610          return NULL;
611      }
612      return ui_method;
613  }
614  
615  /*
616   * BIG FSCKING WARNING!!!! If you use this on a statically allocated method
617   * (that is, it hasn't been allocated using UI_create_method(), you deserve
618   * anything Murphy can throw at you and more! You have been warned.
619   */
UI_destroy_method(UI_METHOD * ui_method)620  void UI_destroy_method(UI_METHOD *ui_method)
621  {
622      if (ui_method == NULL)
623          return;
624      CRYPTO_free_ex_data(CRYPTO_EX_INDEX_UI_METHOD, ui_method,
625                          &ui_method->ex_data);
626      OPENSSL_free(ui_method->name);
627      ui_method->name = NULL;
628      OPENSSL_free(ui_method);
629  }
630  
UI_method_set_opener(UI_METHOD * method,int (* opener)(UI * ui))631  int UI_method_set_opener(UI_METHOD *method, int (*opener) (UI *ui))
632  {
633      if (method != NULL) {
634          method->ui_open_session = opener;
635          return 0;
636      }
637      return -1;
638  }
639  
UI_method_set_writer(UI_METHOD * method,int (* writer)(UI * ui,UI_STRING * uis))640  int UI_method_set_writer(UI_METHOD *method,
641                           int (*writer) (UI *ui, UI_STRING *uis))
642  {
643      if (method != NULL) {
644          method->ui_write_string = writer;
645          return 0;
646      }
647      return -1;
648  }
649  
UI_method_set_flusher(UI_METHOD * method,int (* flusher)(UI * ui))650  int UI_method_set_flusher(UI_METHOD *method, int (*flusher) (UI *ui))
651  {
652      if (method != NULL) {
653          method->ui_flush = flusher;
654          return 0;
655      }
656      return -1;
657  }
658  
UI_method_set_reader(UI_METHOD * method,int (* reader)(UI * ui,UI_STRING * uis))659  int UI_method_set_reader(UI_METHOD *method,
660                           int (*reader) (UI *ui, UI_STRING *uis))
661  {
662      if (method != NULL) {
663          method->ui_read_string = reader;
664          return 0;
665      }
666      return -1;
667  }
668  
UI_method_set_closer(UI_METHOD * method,int (* closer)(UI * ui))669  int UI_method_set_closer(UI_METHOD *method, int (*closer) (UI *ui))
670  {
671      if (method != NULL) {
672          method->ui_close_session = closer;
673          return 0;
674      }
675      return -1;
676  }
677  
UI_method_set_data_duplicator(UI_METHOD * method,void * (* duplicator)(UI * ui,void * ui_data),void (* destructor)(UI * ui,void * ui_data))678  int UI_method_set_data_duplicator(UI_METHOD *method,
679                                    void *(*duplicator) (UI *ui, void *ui_data),
680                                    void (*destructor)(UI *ui, void *ui_data))
681  {
682      if (method != NULL) {
683          method->ui_duplicate_data = duplicator;
684          method->ui_destroy_data = destructor;
685          return 0;
686      }
687      return -1;
688  }
689  
UI_method_set_prompt_constructor(UI_METHOD * method,char * (* prompt_constructor)(UI * ui,const char *,const char *))690  int UI_method_set_prompt_constructor(UI_METHOD *method,
691                                       char *(*prompt_constructor) (UI *ui,
692                                                                    const char *,
693                                                                    const char *))
694  {
695      if (method != NULL) {
696          method->ui_construct_prompt = prompt_constructor;
697          return 0;
698      }
699      return -1;
700  }
701  
UI_method_set_ex_data(UI_METHOD * method,int idx,void * data)702  int UI_method_set_ex_data(UI_METHOD *method, int idx, void *data)
703  {
704      return CRYPTO_set_ex_data(&method->ex_data, idx, data);
705  }
706  
UI_method_get_opener(const UI_METHOD * method)707  int (*UI_method_get_opener(const UI_METHOD *method)) (UI *)
708  {
709      if (method != NULL)
710          return method->ui_open_session;
711      return NULL;
712  }
713  
UI_method_get_writer(const UI_METHOD * method)714  int (*UI_method_get_writer(const UI_METHOD *method)) (UI *, UI_STRING *)
715  {
716      if (method != NULL)
717          return method->ui_write_string;
718      return NULL;
719  }
720  
UI_method_get_flusher(const UI_METHOD * method)721  int (*UI_method_get_flusher(const UI_METHOD *method)) (UI *)
722  {
723      if (method != NULL)
724          return method->ui_flush;
725      return NULL;
726  }
727  
UI_method_get_reader(const UI_METHOD * method)728  int (*UI_method_get_reader(const UI_METHOD *method)) (UI *, UI_STRING *)
729  {
730      if (method != NULL)
731          return method->ui_read_string;
732      return NULL;
733  }
734  
UI_method_get_closer(const UI_METHOD * method)735  int (*UI_method_get_closer(const UI_METHOD *method)) (UI *)
736  {
737      if (method != NULL)
738          return method->ui_close_session;
739      return NULL;
740  }
741  
UI_method_get_prompt_constructor(const UI_METHOD * method)742  char *(*UI_method_get_prompt_constructor(const UI_METHOD *method))
743      (UI *, const char *, const char *)
744  {
745      if (method != NULL)
746          return method->ui_construct_prompt;
747      return NULL;
748  }
749  
UI_method_get_data_duplicator(const UI_METHOD * method)750  void *(*UI_method_get_data_duplicator(const UI_METHOD *method)) (UI *, void *)
751  {
752      if (method != NULL)
753          return method->ui_duplicate_data;
754      return NULL;
755  }
756  
UI_method_get_data_destructor(const UI_METHOD * method)757  void (*UI_method_get_data_destructor(const UI_METHOD *method)) (UI *, void *)
758  {
759      if (method != NULL)
760          return method->ui_destroy_data;
761      return NULL;
762  }
763  
UI_method_get_ex_data(const UI_METHOD * method,int idx)764  const void *UI_method_get_ex_data(const UI_METHOD *method, int idx)
765  {
766      return CRYPTO_get_ex_data(&method->ex_data, idx);
767  }
768  
UI_get_string_type(UI_STRING * uis)769  enum UI_string_types UI_get_string_type(UI_STRING *uis)
770  {
771      return uis->type;
772  }
773  
UI_get_input_flags(UI_STRING * uis)774  int UI_get_input_flags(UI_STRING *uis)
775  {
776      return uis->input_flags;
777  }
778  
UI_get0_output_string(UI_STRING * uis)779  const char *UI_get0_output_string(UI_STRING *uis)
780  {
781      return uis->out_string;
782  }
783  
UI_get0_action_string(UI_STRING * uis)784  const char *UI_get0_action_string(UI_STRING *uis)
785  {
786      switch (uis->type) {
787      case UIT_BOOLEAN:
788          return uis->_.boolean_data.action_desc;
789      case UIT_PROMPT:
790      case UIT_NONE:
791      case UIT_VERIFY:
792      case UIT_INFO:
793      case UIT_ERROR:
794          break;
795      }
796      return NULL;
797  }
798  
UI_get0_result_string(UI_STRING * uis)799  const char *UI_get0_result_string(UI_STRING *uis)
800  {
801      switch (uis->type) {
802      case UIT_PROMPT:
803      case UIT_VERIFY:
804          return uis->result_buf;
805      case UIT_NONE:
806      case UIT_BOOLEAN:
807      case UIT_INFO:
808      case UIT_ERROR:
809          break;
810      }
811      return NULL;
812  }
813  
UI_get_result_string_length(UI_STRING * uis)814  int UI_get_result_string_length(UI_STRING *uis)
815  {
816      switch (uis->type) {
817      case UIT_PROMPT:
818      case UIT_VERIFY:
819          return uis->result_len;
820      case UIT_NONE:
821      case UIT_BOOLEAN:
822      case UIT_INFO:
823      case UIT_ERROR:
824          break;
825      }
826      return -1;
827  }
828  
UI_get0_test_string(UI_STRING * uis)829  const char *UI_get0_test_string(UI_STRING *uis)
830  {
831      switch (uis->type) {
832      case UIT_VERIFY:
833          return uis->_.string_data.test_buf;
834      case UIT_NONE:
835      case UIT_BOOLEAN:
836      case UIT_INFO:
837      case UIT_ERROR:
838      case UIT_PROMPT:
839          break;
840      }
841      return NULL;
842  }
843  
UI_get_result_minsize(UI_STRING * uis)844  int UI_get_result_minsize(UI_STRING *uis)
845  {
846      switch (uis->type) {
847      case UIT_PROMPT:
848      case UIT_VERIFY:
849          return uis->_.string_data.result_minsize;
850      case UIT_NONE:
851      case UIT_INFO:
852      case UIT_ERROR:
853      case UIT_BOOLEAN:
854          break;
855      }
856      return -1;
857  }
858  
UI_get_result_maxsize(UI_STRING * uis)859  int UI_get_result_maxsize(UI_STRING *uis)
860  {
861      switch (uis->type) {
862      case UIT_PROMPT:
863      case UIT_VERIFY:
864          return uis->_.string_data.result_maxsize;
865      case UIT_NONE:
866      case UIT_INFO:
867      case UIT_ERROR:
868      case UIT_BOOLEAN:
869          break;
870      }
871      return -1;
872  }
873  
UI_set_result(UI * ui,UI_STRING * uis,const char * result)874  int UI_set_result(UI *ui, UI_STRING *uis, const char *result)
875  {
876      return UI_set_result_ex(ui, uis, result, strlen(result));
877  }
878  
UI_set_result_ex(UI * ui,UI_STRING * uis,const char * result,int len)879  int UI_set_result_ex(UI *ui, UI_STRING *uis, const char *result, int len)
880  {
881      ui->flags &= ~UI_FLAG_REDOABLE;
882  
883      switch (uis->type) {
884      case UIT_PROMPT:
885      case UIT_VERIFY:
886          if (len < uis->_.string_data.result_minsize) {
887              ui->flags |= UI_FLAG_REDOABLE;
888              ERR_raise_data(ERR_LIB_UI, UI_R_RESULT_TOO_SMALL,
889                             "You must type in %d to %d characters",
890                             uis->_.string_data.result_minsize,
891                             uis->_.string_data.result_maxsize);
892              return -1;
893          }
894          if (len > uis->_.string_data.result_maxsize) {
895              ui->flags |= UI_FLAG_REDOABLE;
896              ERR_raise_data(ERR_LIB_UI, UI_R_RESULT_TOO_LARGE,
897                             "You must type in %d to %d characters",
898                             uis->_.string_data.result_minsize,
899                             uis->_.string_data.result_maxsize);
900              return -1;
901          }
902  
903          if (uis->result_buf == NULL) {
904              ERR_raise(ERR_LIB_UI, UI_R_NO_RESULT_BUFFER);
905              return -1;
906          }
907  
908          memcpy(uis->result_buf, result, len);
909          if (len <= uis->_.string_data.result_maxsize)
910              uis->result_buf[len] = '\0';
911          uis->result_len = len;
912          break;
913      case UIT_BOOLEAN:
914          {
915              const char *p;
916  
917              if (uis->result_buf == NULL) {
918                  ERR_raise(ERR_LIB_UI, UI_R_NO_RESULT_BUFFER);
919                  return -1;
920              }
921  
922              uis->result_buf[0] = '\0';
923              for (p = result; *p; p++) {
924                  if (strchr(uis->_.boolean_data.ok_chars, *p)) {
925                      uis->result_buf[0] = uis->_.boolean_data.ok_chars[0];
926                      break;
927                  }
928                  if (strchr(uis->_.boolean_data.cancel_chars, *p)) {
929                      uis->result_buf[0] = uis->_.boolean_data.cancel_chars[0];
930                      break;
931                  }
932              }
933          }
934      case UIT_NONE:
935      case UIT_INFO:
936      case UIT_ERROR:
937          break;
938      }
939      return 0;
940  }
941