Logo Search packages:      
Sourcecode: openssl version File versions

dso_win32.c

/* dso_win32.c -*- mode:C; c-file-style: "eay" -*- */
/* Written by Geoff Thorpe (geoff@geoffthorpe.net) for the OpenSSL
 * project 2000.
 */
/* ====================================================================
 * Copyright (c) 2000 The OpenSSL Project.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer. 
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. All advertising materials mentioning features or use of this
 *    software must display the following acknowledgment:
 *    "This product includes software developed by the OpenSSL Project
 *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
 *
 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
 *    endorse or promote products derived from this software without
 *    prior written permission. For written permission, please contact
 *    licensing@OpenSSL.org.
 *
 * 5. Products derived from this software may not be called "OpenSSL"
 *    nor may "OpenSSL" appear in their names without prior written
 *    permission of the OpenSSL Project.
 *
 * 6. Redistributions of any form whatsoever must retain the following
 *    acknowledgment:
 *    "This product includes software developed by the OpenSSL Project
 *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
 *
 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 * ====================================================================
 *
 * This product includes cryptographic software written by Eric Young
 * (eay@cryptsoft.com).  This product includes software written by Tim
 * Hudson (tjh@cryptsoft.com).
 *
 */

#include <stdio.h>
#include <string.h>
#include "cryptlib.h"
#include <openssl/dso.h>

#if !defined(DSO_WIN32)
DSO_METHOD *DSO_METHOD_win32(void)
      {
      return NULL;
      }
#else

#ifdef _WIN32_WCE
# if _WIN32_WCE < 300
static FARPROC GetProcAddressA(HMODULE hModule,LPCSTR lpProcName)
      {
      WCHAR lpProcNameW[64];
      int i;

      for (i=0;lpProcName[i] && i<64;i++)
            lpProcNameW[i] = (WCHAR)lpProcName[i];
      if (i==64) return NULL;
      lpProcNameW[i] = 0;

      return GetProcAddressW(hModule,lpProcNameW);
      }
# endif
# undef GetProcAddress
# define GetProcAddress GetProcAddressA

static HINSTANCE LoadLibraryA(LPCSTR lpLibFileName)
      {
      WCHAR *fnamw;
      size_t len_0=strlen(lpLibFileName)+1,i;

#ifdef _MSC_VER
      fnamw = (WCHAR *)_alloca (len_0*sizeof(WCHAR));
#else
      fnamw = (WCHAR *)alloca (len_0*sizeof(WCHAR));
#endif
      if (fnamw == NULL) return NULL;

#if defined(_WIN32_WCE) && _WIN32_WCE>=101
      if (!MultiByteToWideChar(CP_ACP,0,lpLibFileName,len_0,fnamw,len_0))
#endif
            for (i=0;i<len_0;i++) fnamw[i]=(WCHAR)lpLibFileName[i];

      return LoadLibraryW(fnamw);
      }
#endif

/* Part of the hack in "win32_load" ... */
#define DSO_MAX_TRANSLATED_SIZE 256

static int win32_load(DSO *dso);
static int win32_unload(DSO *dso);
static void *win32_bind_var(DSO *dso, const char *symname);
static DSO_FUNC_TYPE win32_bind_func(DSO *dso, const char *symname);
#if 0
static int win32_unbind_var(DSO *dso, char *symname, void *symptr);
static int win32_unbind_func(DSO *dso, char *symname, DSO_FUNC_TYPE symptr);
static int win32_init(DSO *dso);
static int win32_finish(DSO *dso);
static long win32_ctrl(DSO *dso, int cmd, long larg, void *parg);
#endif
static char *win32_name_converter(DSO *dso, const char *filename);
static char *win32_merger(DSO *dso, const char *filespec1,
      const char *filespec2);

static const char *openssl_strnchr(const char *string, int c, size_t len);

static DSO_METHOD dso_meth_win32 = {
      "OpenSSL 'win32' shared library method",
      win32_load,
      win32_unload,
      win32_bind_var,
      win32_bind_func,
/* For now, "unbind" doesn't exist */
#if 0
      NULL, /* unbind_var */
      NULL, /* unbind_func */
#endif
      NULL, /* ctrl */
      win32_name_converter,
      win32_merger,
      NULL, /* init */
      NULL  /* finish */
      };

DSO_METHOD *DSO_METHOD_win32(void)
      {
      return(&dso_meth_win32);
      }

/* For this DSO_METHOD, our meth_data STACK will contain;
 * (i) a pointer to the handle (HINSTANCE) returned from
 *     LoadLibrary(), and copied.
 */

static int win32_load(DSO *dso)
      {
      HINSTANCE h = NULL, *p = NULL;
      /* See applicable comments from dso_dl.c */
      char *filename = DSO_convert_filename(dso, NULL);

      if(filename == NULL)
            {
            DSOerr(DSO_F_WIN32_LOAD,DSO_R_NO_FILENAME);
            goto err;
            }
      h = LoadLibraryA(filename);
      if(h == NULL)
            {
            DSOerr(DSO_F_WIN32_LOAD,DSO_R_LOAD_FAILED);
            ERR_add_error_data(3, "filename(", filename, ")");
            goto err;
            }
      p = (HINSTANCE *)OPENSSL_malloc(sizeof(HINSTANCE));
      if(p == NULL)
            {
            DSOerr(DSO_F_WIN32_LOAD,ERR_R_MALLOC_FAILURE);
            goto err;
            }
      *p = h;
      if(!sk_push(dso->meth_data, (char *)p))
            {
            DSOerr(DSO_F_WIN32_LOAD,DSO_R_STACK_ERROR);
            goto err;
            }
      /* Success */
      dso->loaded_filename = filename;
      return(1);
err:
      /* Cleanup !*/
      if(filename != NULL)
            OPENSSL_free(filename);
      if(p != NULL)
            OPENSSL_free(p);
      if(h != NULL)
            FreeLibrary(h);
      return(0);
      }

static int win32_unload(DSO *dso)
      {
      HINSTANCE *p;
      if(dso == NULL)
            {
            DSOerr(DSO_F_WIN32_UNLOAD,ERR_R_PASSED_NULL_PARAMETER);
            return(0);
            }
      if(sk_num(dso->meth_data) < 1)
            return(1);
      p = (HINSTANCE *)sk_pop(dso->meth_data);
      if(p == NULL)
            {
            DSOerr(DSO_F_WIN32_UNLOAD,DSO_R_NULL_HANDLE);
            return(0);
            }
      if(!FreeLibrary(*p))
            {
            DSOerr(DSO_F_WIN32_UNLOAD,DSO_R_UNLOAD_FAILED);
            /* We should push the value back onto the stack in
             * case of a retry. */
            sk_push(dso->meth_data, (char *)p);
            return(0);
            }
      /* Cleanup */
      OPENSSL_free(p);
      return(1);
      }

/* Using GetProcAddress for variables? TODO: Check this out in
 * the Win32 API docs, there's probably a variant for variables. */
static void *win32_bind_var(DSO *dso, const char *symname)
      {
      HINSTANCE *ptr;
      void *sym;

      if((dso == NULL) || (symname == NULL))
            {
            DSOerr(DSO_F_WIN32_BIND_VAR,ERR_R_PASSED_NULL_PARAMETER);
            return(NULL);
            }
      if(sk_num(dso->meth_data) < 1)
            {
            DSOerr(DSO_F_WIN32_BIND_VAR,DSO_R_STACK_ERROR);
            return(NULL);
            }
      ptr = (HINSTANCE *)sk_value(dso->meth_data, sk_num(dso->meth_data) - 1);
      if(ptr == NULL)
            {
            DSOerr(DSO_F_WIN32_BIND_VAR,DSO_R_NULL_HANDLE);
            return(NULL);
            }
      sym = GetProcAddress(*ptr, symname);
      if(sym == NULL)
            {
            DSOerr(DSO_F_WIN32_BIND_VAR,DSO_R_SYM_FAILURE);
            ERR_add_error_data(3, "symname(", symname, ")");
            return(NULL);
            }
      return(sym);
      }

static DSO_FUNC_TYPE win32_bind_func(DSO *dso, const char *symname)
      {
      HINSTANCE *ptr;
      void *sym;

      if((dso == NULL) || (symname == NULL))
            {
            DSOerr(DSO_F_WIN32_BIND_FUNC,ERR_R_PASSED_NULL_PARAMETER);
            return(NULL);
            }
      if(sk_num(dso->meth_data) < 1)
            {
            DSOerr(DSO_F_WIN32_BIND_FUNC,DSO_R_STACK_ERROR);
            return(NULL);
            }
      ptr = (HINSTANCE *)sk_value(dso->meth_data, sk_num(dso->meth_data) - 1);
      if(ptr == NULL)
            {
            DSOerr(DSO_F_WIN32_BIND_FUNC,DSO_R_NULL_HANDLE);
            return(NULL);
            }
      sym = GetProcAddress(*ptr, symname);
      if(sym == NULL)
            {
            DSOerr(DSO_F_WIN32_BIND_FUNC,DSO_R_SYM_FAILURE);
            ERR_add_error_data(3, "symname(", symname, ")");
            return(NULL);
            }
      return((DSO_FUNC_TYPE)sym);
      }

struct file_st
      {
      const char *node; int nodelen;
      const char *device; int devicelen;
      const char *predir; int predirlen;
      const char *dir; int dirlen;
      const char *file; int filelen;
      };

static struct file_st *win32_splitter(DSO *dso, const char *filename,
      int assume_last_is_dir)
      {
      struct file_st *result = NULL;
      enum { IN_NODE, IN_DEVICE, IN_FILE } position;
      const char *start = filename;
      char last;

      if (!filename)
            {
            DSOerr(DSO_F_WIN32_SPLITTER,DSO_R_NO_FILENAME);
            /*goto err;*/
            return(NULL);
            }

      result = OPENSSL_malloc(sizeof(struct file_st));
      if(result == NULL)
            {
            DSOerr(DSO_F_WIN32_SPLITTER,
                  ERR_R_MALLOC_FAILURE);
            return(NULL);
            }

      memset(result, 0, sizeof(struct file_st));
      position = IN_DEVICE;

      if(filename[0] == '\\' && filename[1] == '\\'
            || filename[0] == '/' && filename[1] == '/')
            {
            position = IN_NODE;
            filename += 2;
            start = filename;
            result->node = start;
            }

      do
            {
            last = filename[0];
            switch(last)
                  {
            case ':':
                  if(position != IN_DEVICE)
                        {
                        DSOerr(DSO_F_WIN32_SPLITTER,
                              DSO_R_INCORRECT_FILE_SYNTAX);
                        /*goto err;*/
                        return(NULL);
                        }
                  result->device = start;
                  result->devicelen = filename - start;
                  position = IN_FILE;
                  start = ++filename;
                  result->dir = start;
                  break;
            case '\\':
            case '/':
                  if(position == IN_NODE)
                        {
                        result->nodelen = filename - start;
                        position = IN_FILE;
                        start = ++filename;
                        result->dir = start;
                        }
                  else if(position == IN_DEVICE)
                        {
                        position = IN_FILE;
                        filename++;
                        result->dir = start;
                        result->dirlen = filename - start;
                        start = filename;
                        }
                  else
                        {
                        filename++;
                        result->dirlen += filename - start;
                        start = filename;
                        }
                  break;
            case '\0':
                  if(position == IN_NODE)
                        {
                        result->nodelen = filename - start;
                        }
                  else
                        {
                        if(filename - start > 0)
                              {
                              if (assume_last_is_dir)
                                    {
                                    if (position == IN_DEVICE)
                                          {
                                          result->dir = start;
                                          result->dirlen = 0;
                                          }
                                    result->dirlen +=
                                          filename - start;
                                    }
                              else
                                    {
                                    result->file = start;
                                    result->filelen =
                                          filename - start;
                                    }
                              }
                        }
                  break;
            default:
                  filename++;
                  break;
                  }
            }
      while(last);

      if(!result->nodelen) result->node = NULL;
      if(!result->devicelen) result->device = NULL;
      if(!result->dirlen) result->dir = NULL;
      if(!result->filelen) result->file = NULL;

      return(result);
      }

static char *win32_joiner(DSO *dso, const struct file_st *file_split)
      {
      int len = 0, offset = 0;
      char *result = NULL;
      const char *start;

      if(!file_split)
            {
            DSOerr(DSO_F_WIN32_JOINER,
                        ERR_R_PASSED_NULL_PARAMETER);
            return(NULL);
            }
      if(file_split->node)
            {
            len += 2 + file_split->nodelen;     /* 2 for starting \\ */
            if(file_split->predir || file_split->dir || file_split->file)
                  len++;      /* 1 for ending \ */
            }
      else if(file_split->device)
            {
            len += file_split->devicelen + 1; /* 1 for ending : */
            }
      len += file_split->predirlen;
      if(file_split->predir && (file_split->dir || file_split->file))
            {
            len++;      /* 1 for ending \ */
            }
      len += file_split->dirlen;
      if(file_split->dir && file_split->file)
            {
            len++;      /* 1 for ending \ */
            }
      len += file_split->filelen;

      if(!len)
            {
            DSOerr(DSO_F_WIN32_JOINER, DSO_R_EMPTY_FILE_STRUCTURE);
            return(NULL);
            }

      result = OPENSSL_malloc(len + 1);
      if (!result)
            {
            DSOerr(DSO_F_WIN32_JOINER,
                  ERR_R_MALLOC_FAILURE);
            return(NULL);
            }

      if(file_split->node)
            {
            strcpy(&result[offset], "\\\\"); offset += 2;
            strncpy(&result[offset], file_split->node,
                  file_split->nodelen); offset += file_split->nodelen;
            if(file_split->predir || file_split->dir || file_split->file)
                  {
                  result[offset] = '\\'; offset++;
                  }
            }
      else if(file_split->device)
            {
            strncpy(&result[offset], file_split->device,
                  file_split->devicelen); offset += file_split->devicelen;
            result[offset] = ':'; offset++;
            }
      start = file_split->predir;
      while(file_split->predirlen > (start - file_split->predir))
            {
            const char *end = openssl_strnchr(start, '/',
                  file_split->predirlen - (start - file_split->predir));
            if(!end)
                  end = start
                        + file_split->predirlen
                        - (start - file_split->predir);
            strncpy(&result[offset], start,
                  end - start); offset += end - start;
            result[offset] = '\\'; offset++;
            start = end + 1;
            }
#if 0 /* Not needed, since the directory converter above already appeneded
       a backslash */
      if(file_split->predir && (file_split->dir || file_split->file))
            {
            result[offset] = '\\'; offset++;
            }
#endif
      start = file_split->dir;
      while(file_split->dirlen > (start - file_split->dir))
            {
            const char *end = openssl_strnchr(start, '/',
                  file_split->dirlen - (start - file_split->dir));
            if(!end)
                  end = start
                        + file_split->dirlen
                        - (start - file_split->dir);
            strncpy(&result[offset], start,
                  end - start); offset += end - start;
            result[offset] = '\\'; offset++;
            start = end + 1;
            }
#if 0 /* Not needed, since the directory converter above already appeneded
       a backslash */
      if(file_split->dir && file_split->file)
            {
            result[offset] = '\\'; offset++;
            }
#endif
      strncpy(&result[offset], file_split->file,
            file_split->filelen); offset += file_split->filelen;
      result[offset] = '\0';
      return(result);
      }

static char *win32_merger(DSO *dso, const char *filespec1, const char *filespec2)
      {
      char *merged = NULL;
      struct file_st *filespec1_split = NULL;
      struct file_st *filespec2_split = NULL;

      if(!filespec1 && !filespec2)
            {
            DSOerr(DSO_F_WIN32_MERGER,
                        ERR_R_PASSED_NULL_PARAMETER);
            return(NULL);
            }
      if (!filespec2)
            {
            merged = OPENSSL_malloc(strlen(filespec1) + 1);
            if(!merged)
                  {
                  DSOerr(DSO_F_WIN32_MERGER,
                        ERR_R_MALLOC_FAILURE);
                  return(NULL);
                  }
            strcpy(merged, filespec1);
            }
      else if (!filespec1)
            {
            merged = OPENSSL_malloc(strlen(filespec2) + 1);
            if(!merged)
                  {
                  DSOerr(DSO_F_WIN32_MERGER,
                        ERR_R_MALLOC_FAILURE);
                  return(NULL);
                  }
            strcpy(merged, filespec2);
            }
      else
            {
            filespec1_split = win32_splitter(dso, filespec1, 0);
            if (!filespec1_split)
                  {
                  DSOerr(DSO_F_WIN32_MERGER,
                        ERR_R_MALLOC_FAILURE);
                  return(NULL);
                  }
            filespec2_split = win32_splitter(dso, filespec2, 1);
            if (!filespec2_split)
                  {
                  DSOerr(DSO_F_WIN32_MERGER,
                        ERR_R_MALLOC_FAILURE);
                  OPENSSL_free(filespec1_split);
                  return(NULL);
                  }

            /* Fill in into filespec1_split */
            if (!filespec1_split->node && !filespec1_split->device)
                  {
                  filespec1_split->node = filespec2_split->node;
                  filespec1_split->nodelen = filespec2_split->nodelen;
                  filespec1_split->device = filespec2_split->device;
                  filespec1_split->devicelen = filespec2_split->devicelen;
                  }
            if (!filespec1_split->dir)
                  {
                  filespec1_split->dir = filespec2_split->dir;
                  filespec1_split->dirlen = filespec2_split->dirlen;
                  }
            else if (filespec1_split->dir[0] != '\\'
                  && filespec1_split->dir[0] != '/')
                  {
                  filespec1_split->predir = filespec2_split->dir;
                  filespec1_split->predirlen = filespec2_split->dirlen;
                  }
            if (!filespec1_split->file)
                  {
                  filespec1_split->file = filespec2_split->file;
                  filespec1_split->filelen = filespec2_split->filelen;
                  }

            merged = win32_joiner(dso, filespec1_split);
            }
      return(merged);
      }

static char *win32_name_converter(DSO *dso, const char *filename)
      {
      char *translated;
      int len, transform;

      len = strlen(filename);
      transform = ((strstr(filename, "/") == NULL) &&
                  (strstr(filename, "\\") == NULL) &&
                  (strstr(filename, ":") == NULL));
      if(transform)
            /* We will convert this to "%s.dll" */
            translated = OPENSSL_malloc(len + 5);
      else
            /* We will simply duplicate filename */
            translated = OPENSSL_malloc(len + 1);
      if(translated == NULL)
            {
            DSOerr(DSO_F_WIN32_NAME_CONVERTER,
                        DSO_R_NAME_TRANSLATION_FAILED); 
            return(NULL);   
            }
      if(transform)
            sprintf(translated, "%s.dll", filename);
      else
            sprintf(translated, "%s", filename);
      return(translated);
      }

static const char *openssl_strnchr(const char *string, int c, size_t len)
      {
      size_t i;
      const char *p;
      for (i = 0, p = string; i < len && *p; i++, p++)
            {
            if (*p == c)
                  return p;
            }
      return NULL;
      }


#endif /* OPENSSL_SYS_WIN32 */

Generated by  Doxygen 1.6.0   Back to index