A good use of the UI interface is as a password callback replacement
[openssl.git] / crypto / ui / ui_lib.c
1 /* crypto/ui/ui_lib.c -*- mode:C; c-file-style: "eay" -*- */
2 /* Written by Richard Levitte (levitte@stacken.kth.se) for the OpenSSL
3  * project 2000.
4  */
5 /* ====================================================================
6  * Copyright (c) 1998-2000 The OpenSSL Project.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer. 
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in
17  *    the documentation and/or other materials provided with the
18  *    distribution.
19  *
20  * 3. All advertising materials mentioning features or use of this
21  *    software must display the following acknowledgment:
22  *    "This product includes software developed by the OpenSSL Project
23  *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
24  *
25  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
26  *    endorse or promote products derived from this software without
27  *    prior written permission. For written permission, please contact
28  *    openssl-core@openssl.org.
29  *
30  * 5. Products derived from this software may not be called "OpenSSL"
31  *    nor may "OpenSSL" appear in their names without prior written
32  *    permission of the OpenSSL Project.
33  *
34  * 6. Redistributions of any form whatsoever must retain the following
35  *    acknowledgment:
36  *    "This product includes software developed by the OpenSSL Project
37  *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
38  *
39  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
43  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50  * OF THE POSSIBILITY OF SUCH DAMAGE.
51  * ====================================================================
52  *
53  * This product includes cryptographic software written by Eric Young
54  * (eay@cryptsoft.com).  This product includes software written by Tim
55  * Hudson (tjh@cryptsoft.com).
56  *
57  */
58
59 #include <openssl/e_os2.h>
60 /* The following defines enable the declaration of strdup(), which is an
61    extended function according to X/Open. */
62 #ifdef OPENSSL_SYS_VMS_DECC
63 # define _XOPEN_SOURCE_EXTENDED
64 #endif
65 #ifdef OPENSSL_SYS_UNIX
66 # define __USE_XOPEN_EXTENDED   /* For Linux and probably anything GNU */
67 #endif
68 #include <string.h>
69
70 #include <openssl/ui.h>
71 #include <openssl/err.h>
72 #include "ui_locl.h"
73
74 IMPLEMENT_STACK_OF(UI_STRING_ST)
75
76 static const UI_METHOD *default_UI_meth=NULL;
77 static int ui_meth_num=0;
78 static STACK_OF(CRYPTO_EX_DATA_FUNCS) *ui_meth=NULL;
79
80 UI *UI_new(void)
81         {
82         return(UI_new_method(NULL));
83         }
84
85 UI *UI_new_method(const UI_METHOD *method)
86         {
87         UI *ret;
88
89         ret=(UI *)OPENSSL_malloc(sizeof(UI));
90         if (ret == NULL)
91                 {
92                 UIerr(UI_F_UI_NEW_METHOD,ERR_R_MALLOC_FAILURE);
93                 return NULL;
94                 }
95         if (method == NULL)
96                 ret->meth=UI_get_default_method();
97         else
98                 ret->meth=method;
99
100         ret->strings=NULL;
101         return ret;
102         }
103
104 static void free_string(UI_STRING *uis)
105         {
106         if (uis->flags & OUT_STRING_FREEABLE)
107                 OPENSSL_free((char *)uis->out_string);
108         OPENSSL_free(uis);
109         }
110
111 void UI_free(UI *ui)
112         {
113         sk_UI_STRING_pop_free(ui->strings,free_string);
114         OPENSSL_free(ui);
115         }
116
117 static int allocate_string_stack(UI *ui)
118         {
119         if (ui->strings == NULL)
120                 {
121                 ui->strings=sk_UI_STRING_new_null();
122                 if (ui->strings == NULL)
123                         {
124                         return -1;
125                         }
126                 }
127         return 0;
128         }
129
130 static int general_allocate_string(UI *ui, const char *prompt,
131         int prompt_freeable, enum UI_string_types type,
132         char *result_buf, int minsize, int maxsize, const char *test_buf)
133         {
134         int ret=-1;
135
136         if (prompt == NULL)
137                 {
138                 UIerr(UI_F_GENERAL_ALLOCATE_STRING,ERR_R_PASSED_NULL_PARAMETER);
139                 }
140         else if (allocate_string_stack(ui) >= 0)
141                 {
142                 UI_STRING *s=(UI_STRING *)OPENSSL_malloc(sizeof(UI_STRING));
143                 s->out_string=prompt;
144                 s->flags=prompt_freeable ? OUT_STRING_FREEABLE : 0;
145                 s->type=type;
146                 s->result_buf=result_buf;
147                 s->result_minsize=minsize;
148                 s->result_maxsize=maxsize;
149                 s->test_buf=test_buf;
150                 ret=sk_UI_STRING_push(ui->strings, s);
151                 }
152         return ret;
153         }
154
155 /* Returns the index to the place in the stack or 0 for error.  Uses a
156    direct reference to the prompt.  */
157 int UI_add_input_string(UI *ui, const char *prompt, int echo_p,
158         char *result_buf, int minsize, int maxsize)
159         {
160         return general_allocate_string(ui, prompt, 0,
161                 echo_p?UI_STRING_ECHO:UI_STRING_NOECHO,
162                 result_buf, minsize, maxsize, NULL);
163         }
164
165 /* Same as UI_add_input_string(), excepts it takes a copy of the prompt */
166 int UI_dup_input_string(UI *ui, const char *prompt, int echo_p,
167         char *result_buf, int minsize, int maxsize)
168         {
169         char *prompt_copy=NULL;
170
171         if (prompt)
172                 {
173                 prompt_copy=strdup(prompt);
174                 if (prompt_copy == NULL)
175                         {
176                         UIerr(UI_F_UI_DUP_INPUT_STRING,ERR_R_MALLOC_FAILURE);
177                         return 0;
178                         }
179                 }
180         
181         return general_allocate_string(ui, prompt, 1,
182                 echo_p?UI_STRING_ECHO:UI_STRING_NOECHO,
183                 result_buf, minsize, maxsize, NULL);
184         }
185
186 int UI_add_verify_string(UI *ui, const char *prompt, int echo_p,
187         char *result_buf, int minsize, int maxsize, const char *test_buf)
188         {
189         return general_allocate_string(ui, prompt, 0,
190                 echo_p?UI_VERIFY_ECHO:UI_VERIFY_NOECHO,
191                 result_buf, minsize, maxsize, test_buf);
192         }
193
194 int UI_dup_verify_string(UI *ui, const char *prompt, int echo_p,
195         char *result_buf, int minsize, int maxsize, const char *test_buf)
196         {
197         char *prompt_copy=NULL;
198
199         if (prompt)
200                 {
201                 prompt_copy=strdup(prompt);
202                 if (prompt_copy == NULL)
203                         {
204                         UIerr(UI_F_UI_DUP_VERIFY_STRING,ERR_R_MALLOC_FAILURE);
205                         return -1;
206                         }
207                 }
208         
209         return general_allocate_string(ui, prompt, 1,
210                 echo_p?UI_VERIFY_ECHO:UI_VERIFY_NOECHO,
211                 result_buf, minsize, maxsize, test_buf);
212         }
213
214 int UI_add_info_string(UI *ui, const char *text)
215         {
216         return general_allocate_string(ui, text, 0, UI_INFO, NULL, 0, 0, NULL);
217         }
218
219 int UI_dup_info_string(UI *ui, const char *text)
220         {
221         char *text_copy=NULL;
222
223         if (text)
224                 {
225                 text_copy=strdup(text);
226                 if (text_copy == NULL)
227                         {
228                         UIerr(UI_F_UI_DUP_INFO_STRING,ERR_R_MALLOC_FAILURE);
229                         return -1;
230                         }
231                 }
232
233         return general_allocate_string(ui, text, 1, UI_INFO, NULL, 0, 0, NULL);
234         }
235
236 int UI_add_error_string(UI *ui, const char *text)
237         {
238         return general_allocate_string(ui, text, 0, UI_ERROR, NULL, 0, 0,
239                 NULL);
240         }
241
242 int UI_dup_error_string(UI *ui, const char *text)
243         {
244         char *text_copy=NULL;
245
246         if (text)
247                 {
248                 text_copy=strdup(text);
249                 if (text_copy == NULL)
250                         {
251                         UIerr(UI_F_UI_DUP_ERROR_STRING,ERR_R_MALLOC_FAILURE);
252                         return -1;
253                         }
254                 }
255         return general_allocate_string(ui, text_copy, 1, UI_ERROR, NULL, 0, 0,
256                 NULL);
257         }
258
259 void *UI_add_user_data(UI *ui, void *user_data)
260         {
261         void *old_data = ui->user_data;
262         ui->user_data = user_data;
263         return old_data;
264         }
265
266 void *UI_get0_user_data(UI *ui)
267         {
268         return ui->user_data;
269         }
270
271 const char *UI_get0_result(UI *ui, int i)
272         {
273         if (i < 0)
274                 {
275                 UIerr(UI_F_UI_GET0_RESULT,UI_R_INDEX_TOO_SMALL);
276                 return NULL;
277                 }
278         if (i >= sk_UI_STRING_num(ui->strings))
279                 {
280                 UIerr(UI_F_UI_GET0_RESULT,UI_R_INDEX_TOO_LARGE);
281                 return NULL;
282                 }
283         return UI_get0_result_string(sk_UI_STRING_value(ui->strings, i));
284         }
285
286 int UI_process(UI *ui)
287         {
288         int i, ok=0;
289
290         if (ui->meth->ui_open_session && !ui->meth->ui_open_session(ui))
291                 return -1;
292
293         for(i=0; i<sk_UI_STRING_num(ui->strings); i++)
294                 {
295                 if (ui->meth->ui_write_string
296                         && !ui->meth->ui_write_string(ui,
297                                 sk_UI_STRING_value(ui->strings, i)))
298                         {
299                         ok=-1;
300                         goto err;
301                         }
302                 }
303
304         for(i=0; i<sk_UI_STRING_num(ui->strings); i++)
305                 {
306                 if (ui->meth->ui_read_string
307                         && !ui->meth->ui_read_string(ui,
308                                 sk_UI_STRING_value(ui->strings, i)))
309                         {
310                         ok=-1;
311                         goto err;
312                         }
313                 }
314  err:
315         if (ui->meth->ui_close_session && !ui->meth->ui_close_session(ui))
316                 return -1;
317         return ok;
318         }
319
320 int UI_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
321              CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func)
322         {
323         ui_meth_num++;
324         return(CRYPTO_get_ex_new_index(ui_meth_num-1,
325                 &ui_meth,argl,argp,new_func,dup_func,free_func));
326         }
327
328 int UI_set_ex_data(UI *r, int idx, void *arg)
329         {
330         return(CRYPTO_set_ex_data(&r->ex_data,idx,arg));
331         }
332
333 void *UI_get_ex_data(UI *r, int idx)
334         {
335         return(CRYPTO_get_ex_data(&r->ex_data,idx));
336         }
337
338 void UI_set_default_method(const UI_METHOD *meth)
339         {
340         default_UI_meth=meth;
341         }
342
343 const UI_METHOD *UI_get_default_method(void)
344         {
345         if (default_UI_meth == NULL)
346                 {
347                 default_UI_meth=UI_OpenSSL();
348                 }
349         return default_UI_meth;
350         }
351
352 const UI_METHOD *UI_get_method(UI *ui)
353         {
354         return ui->meth;
355         }
356
357 const UI_METHOD *UI_set_method(UI *ui, const UI_METHOD *meth)
358         {
359         ui->meth=meth;
360         return ui->meth;
361         }
362
363
364 UI_METHOD *UI_create_method(void)
365         {
366         return (UI_METHOD *)OPENSSL_malloc(sizeof(UI_METHOD));
367         }
368
369 int UI_method_set_opener(UI_METHOD *method, int (*opener)(UI *ui))
370         {
371         if (method)
372                 {
373                 method->ui_open_session = opener;
374                 return 0;
375                 }
376         else
377                 return -1;
378         }
379
380 int UI_method_set_writer(UI_METHOD *method, int (*writer)(UI *ui, UI_STRING *uis))
381         {
382         if (method)
383                 {
384                 method->ui_write_string = writer;
385                 return 0;
386                 }
387         else
388                 return -1;
389         }
390
391 int UI_method_set_reader(UI_METHOD *method, int (*reader)(UI *ui, UI_STRING *uis))
392         {
393         if (method)
394                 {
395                 method->ui_read_string = reader;
396                 return 0;
397                 }
398         else
399                 return -1;
400         }
401
402 int UI_method_set_closer(UI_METHOD *method, int (*closer)(UI *ui))
403         {
404         if (method)
405                 {
406                 method->ui_close_session = closer;
407                 return 0;
408                 }
409         else
410                 return -1;
411         }
412
413 int (*UI_method_get_opener(UI_METHOD *method))(UI*)
414         {
415         if (method)
416                 return method->ui_open_session;
417         else
418                 return NULL;
419         }
420
421 int (*UI_method_get_writer(UI_METHOD *method))(UI*,UI_STRING*)
422         {
423         if (method)
424                 return method->ui_write_string;
425         else
426                 return NULL;
427         }
428
429 int (*UI_method_get_reader(UI_METHOD *method))(UI*,UI_STRING*)
430         {
431         if (method)
432                 return method->ui_read_string;
433         else
434                 return NULL;
435         }
436
437 int (*UI_method_get_closer(UI_METHOD *method))(UI*)
438         {
439         if (method)
440                 return method->ui_close_session;
441         else
442                 return NULL;
443         }
444
445 enum UI_string_types UI_get_string_type(UI_STRING *uis)
446         {
447         if (!uis)
448                 return UI_NONE;
449         return uis->type;
450         }
451
452 const char *UI_get0_output_string(UI_STRING *uis)
453         {
454         if (!uis)
455                 return NULL;
456         return uis->out_string;
457         }
458
459 const char *UI_get0_result_string(UI_STRING *uis)
460         {
461         if (!uis)
462                 return NULL;
463         switch(uis->type)
464                 {
465         case UI_STRING_ECHO:
466         case UI_STRING_NOECHO:
467         case UI_VERIFY_ECHO:
468         case UI_VERIFY_NOECHO:
469                 return uis->result_buf;
470         default:
471                 return NULL;
472                 }
473         }
474
475 const char *UI_get0_test_string(UI_STRING *uis)
476         {
477         if (!uis)
478                 return NULL;
479         return uis->test_buf;
480         }
481
482 int UI_get_result_minsize(UI_STRING *uis)
483         {
484         if (!uis)
485                 return -1;
486         return uis->result_minsize;
487         }
488
489 int UI_get_result_maxsize(UI_STRING *uis)
490         {
491         if (!uis)
492                 return -1;
493         return uis->result_maxsize;
494         }
495
496 int UI_set_result(UI_STRING *uis, char *result)
497         {
498         int l = strlen(result);
499
500         if (!uis)
501                 return -1;
502         if (l < uis->result_minsize)
503                 {
504                 UIerr(UI_F_UI_SET_RESULT,UI_R_RESULT_TOO_SMALL);
505                 return -1;
506                 }
507         if (l > uis->result_maxsize)
508                 {
509                 UIerr(UI_F_UI_SET_RESULT,UI_R_RESULT_TOO_LARGE);
510                 return -1;
511                 }
512
513         if (!uis->result_buf)
514                 {
515                 uis->result_buf = OPENSSL_malloc(uis->result_maxsize+1);
516                 }
517
518         if (!uis->result_buf)
519                 {
520                 UIerr(UI_F_UI_NEW_METHOD,ERR_R_MALLOC_FAILURE);
521                 return -1;
522                 }
523
524         strcpy(uis->result_buf, result);
525         return 0;
526         }