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