e6eaa990052365112d4c163dc65b06e3c5961a97
[openssl.git] / crypto / dso / dso_win32.c
1 /* dso_win32.c -*- mode:C; c-file-style: "eay" -*- */
2 /* Written by Geoff Thorpe (geoff@geoffthorpe.net) for the OpenSSL
3  * project 2000.
4  */
5 /* ====================================================================
6  * Copyright (c) 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  *    licensing@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 <stdio.h>
60 #include <string.h>
61 #include "cryptlib.h"
62 #include <openssl/dso.h>
63
64 #if !defined(DSO_WIN32)
65 DSO_METHOD *DSO_METHOD_win32(void)
66         {
67         return NULL;
68         }
69 #else
70
71 /* Part of the hack in "win32_load" ... */
72 #define DSO_MAX_TRANSLATED_SIZE 256
73
74 static int win32_load(DSO *dso);
75 static int win32_unload(DSO *dso);
76 static void *win32_bind_var(DSO *dso, const char *symname);
77 static DSO_FUNC_TYPE win32_bind_func(DSO *dso, const char *symname);
78 #if 0
79 static int win32_unbind_var(DSO *dso, char *symname, void *symptr);
80 static int win32_unbind_func(DSO *dso, char *symname, DSO_FUNC_TYPE symptr);
81 static int win32_init(DSO *dso);
82 static int win32_finish(DSO *dso);
83 static long win32_ctrl(DSO *dso, int cmd, long larg, void *parg);
84 #endif
85 static char *win32_name_converter(DSO *dso, const char *filename);
86 static char *win32_merger(DSO *dso, const char *filespec1,
87         const char *filespec2);
88
89 static const char *openssl_strnchr(const char *string, int c, size_t len);
90
91 static DSO_METHOD dso_meth_win32 = {
92         "OpenSSL 'win32' shared library method",
93         win32_load,
94         win32_unload,
95         win32_bind_var,
96         win32_bind_func,
97 /* For now, "unbind" doesn't exist */
98 #if 0
99         NULL, /* unbind_var */
100         NULL, /* unbind_func */
101 #endif
102         NULL, /* ctrl */
103         win32_name_converter,
104         win32_merger,
105         NULL, /* init */
106         NULL  /* finish */
107         };
108
109 DSO_METHOD *DSO_METHOD_win32(void)
110         {
111         return(&dso_meth_win32);
112         }
113
114 /* For this DSO_METHOD, our meth_data STACK will contain;
115  * (i) a pointer to the handle (HINSTANCE) returned from
116  *     LoadLibrary(), and copied.
117  */
118
119 static int win32_load(DSO *dso)
120         {
121         HINSTANCE h = NULL, *p = NULL;
122         /* See applicable comments from dso_dl.c */
123         char *filename = DSO_convert_filename(dso, NULL);
124
125         if(filename == NULL)
126                 {
127                 DSOerr(DSO_F_WIN32_LOAD,DSO_R_NO_FILENAME);
128                 goto err;
129                 }
130         h = LoadLibrary(filename);
131         if(h == NULL)
132                 {
133                 DSOerr(DSO_F_WIN32_LOAD,DSO_R_LOAD_FAILED);
134                 ERR_add_error_data(3, "filename(", filename, ")");
135                 goto err;
136                 }
137         p = (HINSTANCE *)OPENSSL_malloc(sizeof(HINSTANCE));
138         if(p == NULL)
139                 {
140                 DSOerr(DSO_F_WIN32_LOAD,ERR_R_MALLOC_FAILURE);
141                 goto err;
142                 }
143         *p = h;
144         if(!sk_push(dso->meth_data, (char *)p))
145                 {
146                 DSOerr(DSO_F_WIN32_LOAD,DSO_R_STACK_ERROR);
147                 goto err;
148                 }
149         /* Success */
150         dso->loaded_filename = filename;
151         return(1);
152 err:
153         /* Cleanup !*/
154         if(filename != NULL)
155                 OPENSSL_free(filename);
156         if(p != NULL)
157                 OPENSSL_free(p);
158         if(h != NULL)
159                 FreeLibrary(h);
160         return(0);
161         }
162
163 static int win32_unload(DSO *dso)
164         {
165         HINSTANCE *p;
166         if(dso == NULL)
167                 {
168                 DSOerr(DSO_F_WIN32_UNLOAD,ERR_R_PASSED_NULL_PARAMETER);
169                 return(0);
170                 }
171         if(sk_num(dso->meth_data) < 1)
172                 return(1);
173         p = (HINSTANCE *)sk_pop(dso->meth_data);
174         if(p == NULL)
175                 {
176                 DSOerr(DSO_F_WIN32_UNLOAD,DSO_R_NULL_HANDLE);
177                 return(0);
178                 }
179         if(!FreeLibrary(*p))
180                 {
181                 DSOerr(DSO_F_WIN32_UNLOAD,DSO_R_UNLOAD_FAILED);
182                 /* We should push the value back onto the stack in
183                  * case of a retry. */
184                 sk_push(dso->meth_data, (char *)p);
185                 return(0);
186                 }
187         /* Cleanup */
188         OPENSSL_free(p);
189         return(1);
190         }
191
192 /* Using GetProcAddress for variables? TODO: Check this out in
193  * the Win32 API docs, there's probably a variant for variables. */
194 static void *win32_bind_var(DSO *dso, const char *symname)
195         {
196         HINSTANCE *ptr;
197         void *sym;
198
199         if((dso == NULL) || (symname == NULL))
200                 {
201                 DSOerr(DSO_F_WIN32_BIND_VAR,ERR_R_PASSED_NULL_PARAMETER);
202                 return(NULL);
203                 }
204         if(sk_num(dso->meth_data) < 1)
205                 {
206                 DSOerr(DSO_F_WIN32_BIND_VAR,DSO_R_STACK_ERROR);
207                 return(NULL);
208                 }
209         ptr = (HINSTANCE *)sk_value(dso->meth_data, sk_num(dso->meth_data) - 1);
210         if(ptr == NULL)
211                 {
212                 DSOerr(DSO_F_WIN32_BIND_VAR,DSO_R_NULL_HANDLE);
213                 return(NULL);
214                 }
215         sym = GetProcAddress(*ptr, symname);
216         if(sym == NULL)
217                 {
218                 DSOerr(DSO_F_WIN32_BIND_VAR,DSO_R_SYM_FAILURE);
219                 ERR_add_error_data(3, "symname(", symname, ")");
220                 return(NULL);
221                 }
222         return(sym);
223         }
224
225 static DSO_FUNC_TYPE win32_bind_func(DSO *dso, const char *symname)
226         {
227         HINSTANCE *ptr;
228         void *sym;
229
230         if((dso == NULL) || (symname == NULL))
231                 {
232                 DSOerr(DSO_F_WIN32_BIND_FUNC,ERR_R_PASSED_NULL_PARAMETER);
233                 return(NULL);
234                 }
235         if(sk_num(dso->meth_data) < 1)
236                 {
237                 DSOerr(DSO_F_WIN32_BIND_FUNC,DSO_R_STACK_ERROR);
238                 return(NULL);
239                 }
240         ptr = (HINSTANCE *)sk_value(dso->meth_data, sk_num(dso->meth_data) - 1);
241         if(ptr == NULL)
242                 {
243                 DSOerr(DSO_F_WIN32_BIND_FUNC,DSO_R_NULL_HANDLE);
244                 return(NULL);
245                 }
246         sym = GetProcAddress(*ptr, symname);
247         if(sym == NULL)
248                 {
249                 DSOerr(DSO_F_WIN32_BIND_FUNC,DSO_R_SYM_FAILURE);
250                 ERR_add_error_data(3, "symname(", symname, ")");
251                 return(NULL);
252                 }
253         return((DSO_FUNC_TYPE)sym);
254         }
255
256 struct file_st
257         {
258         const char *node; int nodelen;
259         const char *device; int devicelen;
260         const char *predir; int predirlen;
261         const char *dir; int dirlen;
262         const char *file; int filelen;
263         };
264
265 static struct file_st *win32_splitter(DSO *dso, const char *filename,
266         int assume_last_is_dir)
267         {
268         struct file_st *result = NULL;
269         enum { IN_NODE, IN_DEVICE, IN_FILE } position;
270         const char *start = filename;
271
272         if (!filename)
273                 {
274                 DSOerr(DSO_F_WIN32_SPLITTER,DSO_R_NO_FILENAME);
275                 /*goto err;*/
276                 return(NULL);
277                 }
278
279         result = OPENSSL_malloc(sizeof(struct file_st));
280         if(result == NULL)
281                 {
282                 DSOerr(DSO_F_WIN32_SPLITTER,
283                         ERR_R_MALLOC_FAILURE);
284                 return(NULL);
285                 }
286
287         memset(result, 0, sizeof(struct file_st));
288         position = IN_DEVICE;
289
290         if(filename[0] == '\\' && filename[1] == '\\'
291                 || filename[0] == '/' && filename[1] == '/')
292                 {
293                 position = IN_NODE;
294                 filename += 2;
295                 start = filename;
296                 result->node = start;
297                 }
298
299         do
300                 {
301                 switch(filename[0])
302                         {
303                 case ':':
304                         if(position != IN_DEVICE)
305                                 {
306                                 DSOerr(DSO_F_WIN32_SPLITTER,
307                                         DSO_R_INCORRECT_FILE_SYNTAX);
308                                 /*goto err;*/
309                                 return(NULL);
310                                 }
311                         result->device = start;
312                         result->devicelen = filename - start;
313                         position = IN_FILE;
314                         start = ++filename;
315                         result->dir = start;
316                         break;
317                 case '\\':
318                 case '/':
319                         if(position == IN_NODE)
320                                 {
321                                 result->nodelen = filename - start;
322                                 position = IN_FILE;
323                                 start = ++filename;
324                                 result->dir = start;
325                                 }
326                         else
327                                 {
328                                 filename++;
329                                 result->dirlen += filename - start;
330                                 }
331                         break;
332                 case '\0':
333                         if(position == IN_NODE)
334                                 {
335                                 result->nodelen = filename - start;
336                                 }
337                         else
338                                 {
339                                 if(filename - start > 0)
340                                         {
341                                         if (assume_last_is_dir)
342                                                 {
343                                                 result->devicelen += filename - start;
344                                                 }
345                                         else
346                                                 {
347                                                 result->file = start;
348                                                 result->filelen = filename - start;
349                                                 }
350                                         }
351                                 }
352                         break;
353                 default:
354                         filename++;
355                         break;
356                         }
357                 }
358         while(*filename);
359
360         if(!result->nodelen) result->node = NULL;
361         if(!result->devicelen) result->device = NULL;
362         if(!result->dirlen) result->dir = NULL;
363         if(!result->filelen) result->file = NULL;
364
365         return(result);
366         }
367
368 static char *win32_joiner(DSO *dso, const struct file_st *file_split)
369         {
370         int len = 0, offset = 0;
371         char *result = NULL;
372         const char *start;
373
374         if(!file_split)
375                 {
376                 DSOerr(DSO_F_WIN32_JOINER,
377                                 ERR_R_PASSED_NULL_PARAMETER);
378                 return(NULL);
379                 }
380         if(file_split->node)
381                 {
382                 len += 2 + file_split->nodelen; /* 2 for starting \\ */
383                 if(file_split->predir || file_split->dir || file_split->file)
384                         len++;  /* 1 for ending \ */
385                 }
386         else if(file_split->device)
387                 {
388                 len += file_split->devicelen + 1; /* 1 for ending : */
389                 }
390         len += file_split->predirlen;
391         if(file_split->predir && (file_split->dir || file_split->file))
392                 {
393                 len++;  /* 1 for ending \ */
394                 }
395         len += file_split->dirlen;
396         if(file_split->dir && file_split->file)
397                 {
398                 len++;  /* 1 for ending \ */
399                 }
400         len += file_split->filelen;
401
402         if(!len)
403                 {
404                 DSOerr(DSO_F_WIN32_JOINER, DSO_R_EMPTY_FILE_STRUCTURE);
405                 return(NULL);
406                 }
407
408         result = OPENSSL_malloc(len + 1);
409         if (!result)
410                 {
411                 DSOerr(DSO_F_WIN32_JOINER,
412                         ERR_R_MALLOC_FAILURE);
413                 return(NULL);
414                 }
415
416         if(file_split->node)
417                 {
418                 strcpy(&result[offset], "\\\\"); offset += 2;
419                 strncpy(&result[offset], file_split->node,
420                         file_split->nodelen); offset += file_split->nodelen;
421                 if(file_split->predir || file_split->dir || file_split->file)
422                         {
423                         result[offset] = '\\'; offset++;
424                         }
425                 }
426         else if(file_split->device)
427                 {
428                 strncpy(&result[offset], file_split->device,
429                         file_split->devicelen); offset += file_split->devicelen;
430                 result[offset] = ':'; offset++;
431                 }
432         start = file_split->predir;
433         while(file_split->predirlen > (start - file_split->predir))
434                 {
435                 const char *end = openssl_strnchr(start, '/',
436                         file_split->predirlen - (start - file_split->predir));
437                 if(!end)
438                         end = start
439                                 + file_split->predirlen
440                                 - (start - file_split->predir);
441                 strncpy(&result[offset], start,
442                         end - start); offset += end - start;
443                 result[offset] = '\\'; offset++;
444                 start = end + 1;
445                 }
446         if(file_split->predir && (file_split->dir || file_split->file))
447                 {
448                 result[offset] = '\\'; offset++;
449                 }
450         start = file_split->dir;
451         while(file_split->dirlen > (start - file_split->dir))
452                 {
453                 const char *end = openssl_strnchr(start, '/',
454                         file_split->dirlen - (start - file_split->dir));
455                 if(!end)
456                         end = start
457                                 + file_split->dirlen
458                                 - (start - file_split->dir);
459                 strncpy(&result[offset], start,
460                         end - start); offset += end - start;
461                 result[offset] = '\\'; offset++;
462                 start = end + 1;
463                 }
464         if(file_split->dir && file_split->file)
465                 {
466                 result[offset] = '\\'; offset++;
467                 }
468         strncpy(&result[offset], file_split->file,
469                 file_split->filelen); offset += file_split->filelen;
470         result[offset] = '\0';
471         return(result);
472         }
473
474 static char *win32_merger(DSO *dso, const char *filespec1, const char *filespec2)
475         {
476         char *merged = NULL;
477         struct file_st *filespec1_split = NULL;
478         struct file_st *filespec2_split = NULL;
479
480         if(!filespec1 && !filespec2)
481                 {
482                 DSOerr(DSO_F_WIN32_MERGER,
483                                 ERR_R_PASSED_NULL_PARAMETER);
484                 return(NULL);
485                 }
486         if (!filespec2)
487                 {
488                 merged = OPENSSL_malloc(strlen(filespec1) + 1);
489                 if(!merged)
490                         {
491                         DSOerr(DSO_F_WIN32_MERGER,
492                                 ERR_R_MALLOC_FAILURE);
493                         return(NULL);
494                         }
495                 strcpy(merged, filespec1);
496                 }
497         else if (!filespec1)
498                 {
499                 merged = OPENSSL_malloc(strlen(filespec2) + 1);
500                 if(!merged)
501                         {
502                         DSOerr(DSO_F_WIN32_MERGER,
503                                 ERR_R_MALLOC_FAILURE);
504                         return(NULL);
505                         }
506                 strcpy(merged, filespec2);
507                 }
508         else
509                 {
510                 filespec1_split = win32_splitter(dso, filespec1, 1);
511                 if (!filespec1_split)
512                         {
513                         DSOerr(DSO_F_WIN32_MERGER,
514                                 ERR_R_MALLOC_FAILURE);
515                         return(NULL);
516                         }
517                 filespec2_split = win32_splitter(dso, filespec2, 0);
518                 if (!filespec1_split)
519                         {
520                         DSOerr(DSO_F_WIN32_MERGER,
521                                 ERR_R_MALLOC_FAILURE);
522                         OPENSSL_free(filespec1_split);
523                         return(NULL);
524                         }
525
526                 /* Fill in into filespec1_split */
527                 if (!filespec1_split->node && !filespec1_split->device)
528                         {
529                         filespec1_split->node = filespec2_split->node;
530                         filespec1_split->nodelen = filespec2_split->nodelen;
531                         filespec1_split->device = filespec2_split->device;
532                         filespec1_split->devicelen = filespec2_split->devicelen;
533                         }
534                 if (!filespec1_split->dir)
535                         {
536                         filespec1_split->dir = filespec2_split->dir;
537                         filespec1_split->dirlen = filespec2_split->dirlen;
538                         }
539                 else if (filespec1_split->dir[0] != '\\'
540                         && filespec1_split->dir[0] != '/')
541                         {
542                         filespec1_split->predir = filespec2_split->dir;
543                         filespec1_split->predirlen = filespec2_split->dirlen;
544                         }
545                 if (!filespec1_split->file)
546                         {
547                         filespec1_split->file = filespec2_split->file;
548                         filespec1_split->filelen = filespec2_split->filelen;
549                         }
550
551                 merged = win32_joiner(dso, filespec1_split);
552                 }
553         return(merged);
554         }
555
556 static char *win32_name_converter(DSO *dso, const char *filename)
557         {
558         char *translated;
559         int len, transform;
560
561         len = strlen(filename);
562         transform = ((strstr(filename, "/") == NULL) &&
563                         (strstr(filename, "\\") == NULL) &&
564                         (strstr(filename, ":") == NULL));
565         if(transform)
566                 /* We will convert this to "%s.dll" */
567                 translated = OPENSSL_malloc(len + 5);
568         else
569                 /* We will simply duplicate filename */
570                 translated = OPENSSL_malloc(len + 1);
571         if(translated == NULL)
572                 {
573                 DSOerr(DSO_F_WIN32_NAME_CONVERTER,
574                                 DSO_R_NAME_TRANSLATION_FAILED); 
575                 return(NULL);   
576                 }
577         if(transform)
578                 sprintf(translated, "%s.dll", filename);
579         else
580                 sprintf(translated, "%s", filename);
581         return(translated);
582         }
583
584 static const char *openssl_strnchr(const char *string, int c, size_t len)
585         {
586         size_t i;
587         const char *p;
588         for (i = 0, p = string; i < len && *p; i++, p++)
589                 {
590                 if (*p == c)
591                         return p;
592                 }
593         return NULL;
594         }
595
596
597 #endif /* OPENSSL_SYS_WIN32 */