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