1 /* dso_lib.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 <openssl/crypto.h>
  61 #include "cryptlib.h"
  62 #include <openssl/dso.h>
  63 
  64 static DSO_METHOD *default_DSO_meth = NULL;
  65 
  66 DSO *DSO_new(void)
  67         {
  68         return(DSO_new_method(NULL));
  69         }
  70 
  71 void DSO_set_default_method(DSO_METHOD *meth)
  72         {
  73         default_DSO_meth = meth;
  74         }
  75 
  76 DSO_METHOD *DSO_get_default_method(void)
  77         {
  78         return(default_DSO_meth);
  79         }
  80 
  81 DSO_METHOD *DSO_get_method(DSO *dso)
  82         {
  83         return(dso->meth);
  84         }
  85 
  86 DSO_METHOD *DSO_set_method(DSO *dso, DSO_METHOD *meth)
  87         {
  88         DSO_METHOD *mtmp;
  89         mtmp = dso->meth;
  90         dso->meth = meth;
  91         return(mtmp);
  92         }
  93 
  94 DSO *DSO_new_method(DSO_METHOD *meth)
  95         {
  96         DSO *ret;
  97 
  98         if(default_DSO_meth == NULL)
  99                 /* We default to DSO_METH_openssl() which in turn defaults
 100                  * to stealing the "best available" method. Will fallback
 101                  * to DSO_METH_null() in the worst case. */
 102                 default_DSO_meth = DSO_METHOD_openssl();
 103         ret = (DSO *)OPENSSL_malloc(sizeof(DSO));
 104         if(ret == NULL)
 105                 {
 106                 DSOerr(DSO_F_DSO_NEW_METHOD,ERR_R_MALLOC_FAILURE);
 107                 return(NULL);
 108                 }
 109         memset(ret, 0, sizeof(DSO));
 110         ret->meth_data = sk_void_new_null();
 111         if(ret->meth_data == NULL)
 112                 {
 113                 /* sk_new doesn't generate any errors so we do */
 114                 DSOerr(DSO_F_DSO_NEW_METHOD,ERR_R_MALLOC_FAILURE);
 115                 OPENSSL_free(ret);
 116                 return(NULL);
 117                 }
 118         if(meth == NULL)
 119                 ret->meth = default_DSO_meth;
 120         else
 121                 ret->meth = meth;
 122         ret->references = 1;
 123         if((ret->meth->init != NULL) && !ret->meth->init(ret))
 124                 {
 125                 OPENSSL_free(ret);
 126                 ret=NULL;
 127                 }
 128         return(ret);
 129         }
 130 
 131 int DSO_free(DSO *dso)
 132         {
 133         int i;
 134 
 135         if(dso == NULL)
 136                 {
 137                 DSOerr(DSO_F_DSO_FREE,ERR_R_PASSED_NULL_PARAMETER);
 138                 return(0);
 139                 }
 140 
 141         i=CRYPTO_add(&dso->references,-1,CRYPTO_LOCK_DSO);
 142 #ifdef REF_PRINT
 143         REF_PRINT("DSO",dso);
 144 #endif
 145         if(i > 0) return(1);
 146 #ifdef REF_CHECK
 147         if(i < 0)
 148                 {
 149                 fprintf(stderr,"DSO_free, bad reference count\n");
 150                 abort();
 151                 }
 152 #endif
 153 
 154         if((dso->meth->dso_unload != NULL) && !dso->meth->dso_unload(dso))
 155                 {
 156                 DSOerr(DSO_F_DSO_FREE,DSO_R_UNLOAD_FAILED);
 157                 return(0);
 158                 }
 159 
 160         if((dso->meth->finish != NULL) && !dso->meth->finish(dso))
 161                 {
 162                 DSOerr(DSO_F_DSO_FREE,DSO_R_FINISH_FAILED);
 163                 return(0);
 164                 }
 165 
 166         sk_void_free(dso->meth_data);
 167         if(dso->filename != NULL)
 168                 OPENSSL_free(dso->filename);
 169         if(dso->loaded_filename != NULL)
 170                 OPENSSL_free(dso->loaded_filename);
 171 
 172         OPENSSL_free(dso);
 173         return(1);
 174         }
 175 
 176 int DSO_flags(DSO *dso)
 177         {
 178         return((dso == NULL) ? 0 : dso->flags);
 179         }
 180 
 181 
 182 int DSO_up_ref(DSO *dso)
 183         {
 184         if (dso == NULL)
 185                 {
 186                 DSOerr(DSO_F_DSO_UP_REF,ERR_R_PASSED_NULL_PARAMETER);
 187                 return(0);
 188                 }
 189 
 190         CRYPTO_add(&dso->references,1,CRYPTO_LOCK_DSO);
 191         return(1);
 192         }
 193 
 194 DSO *DSO_load(DSO *dso, const char *filename, DSO_METHOD *meth, int flags)
 195         {
 196         DSO *ret;
 197         int allocated = 0;
 198 
 199         if(dso == NULL)
 200                 {
 201                 ret = DSO_new_method(meth);
 202                 if(ret == NULL)
 203                         {
 204                         DSOerr(DSO_F_DSO_LOAD,ERR_R_MALLOC_FAILURE);
 205                         goto err;
 206                         }
 207                 allocated = 1;
 208                 /* Pass the provided flags to the new DSO object */
 209                 if(DSO_ctrl(ret, DSO_CTRL_SET_FLAGS, flags, NULL) < 0)
 210                         {
 211                         DSOerr(DSO_F_DSO_LOAD,DSO_R_CTRL_FAILED);
 212                         goto err;
 213                         }
 214                 }
 215         else
 216                 ret = dso;
 217         /* Don't load if we're currently already loaded */
 218         if(ret->filename != NULL)
 219                 {
 220                 DSOerr(DSO_F_DSO_LOAD,DSO_R_DSO_ALREADY_LOADED);
 221                 goto err;
 222                 }
 223         /* filename can only be NULL if we were passed a dso that already has
 224          * one set. */
 225         if(filename != NULL)
 226                 if(!DSO_set_filename(ret, filename))
 227                         {
 228                         DSOerr(DSO_F_DSO_LOAD,DSO_R_SET_FILENAME_FAILED);
 229                         goto err;
 230                         }
 231         filename = ret->filename;
 232         if(filename == NULL)
 233                 {
 234                 DSOerr(DSO_F_DSO_LOAD,DSO_R_NO_FILENAME);
 235                 goto err;
 236                 }
 237         if(ret->meth->dso_load == NULL)
 238                 {
 239                 DSOerr(DSO_F_DSO_LOAD,DSO_R_UNSUPPORTED);
 240                 goto err;
 241                 }
 242         if(!ret->meth->dso_load(ret))
 243                 {
 244                 DSOerr(DSO_F_DSO_LOAD,DSO_R_LOAD_FAILED);
 245                 goto err;
 246                 }
 247         /* Load succeeded */
 248         return(ret);
 249 err:
 250         if(allocated)
 251                 DSO_free(ret);
 252         return(NULL);
 253         }
 254 
 255 void *DSO_bind_var(DSO *dso, const char *symname)
 256         {
 257         void *ret = NULL;
 258 
 259         if((dso == NULL) || (symname == NULL))
 260                 {
 261                 DSOerr(DSO_F_DSO_BIND_VAR,ERR_R_PASSED_NULL_PARAMETER);
 262                 return(NULL);
 263                 }
 264         if(dso->meth->dso_bind_var == NULL)
 265                 {
 266                 DSOerr(DSO_F_DSO_BIND_VAR,DSO_R_UNSUPPORTED);
 267                 return(NULL);
 268                 }
 269         if((ret = dso->meth->dso_bind_var(dso, symname)) == NULL)
 270                 {
 271                 DSOerr(DSO_F_DSO_BIND_VAR,DSO_R_SYM_FAILURE);
 272                 return(NULL);
 273                 }
 274         /* Success */
 275         return(ret);
 276         }
 277 
 278 DSO_FUNC_TYPE DSO_bind_func(DSO *dso, const char *symname)
 279         {
 280         DSO_FUNC_TYPE ret = NULL;
 281 
 282         if((dso == NULL) || (symname == NULL))
 283                 {
 284                 DSOerr(DSO_F_DSO_BIND_FUNC,ERR_R_PASSED_NULL_PARAMETER);
 285                 return(NULL);
 286                 }
 287         if(dso->meth->dso_bind_func == NULL)
 288                 {
 289                 DSOerr(DSO_F_DSO_BIND_FUNC,DSO_R_UNSUPPORTED);
 290                 return(NULL);
 291                 }
 292         if((ret = dso->meth->dso_bind_func(dso, symname)) == NULL)
 293                 {
 294                 DSOerr(DSO_F_DSO_BIND_FUNC,DSO_R_SYM_FAILURE);
 295                 return(NULL);
 296                 }
 297         /* Success */
 298         return(ret);
 299         }
 300 
 301 /* I don't really like these *_ctrl functions very much to be perfectly
 302  * honest. For one thing, I think I have to return a negative value for
 303  * any error because possible DSO_ctrl() commands may return values
 304  * such as "size"s that can legitimately be zero (making the standard
 305  * "if(DSO_cmd(...))" form that works almost everywhere else fail at
 306  * odd times. I'd prefer "output" values to be passed by reference and
 307  * the return value as success/failure like usual ... but we conform
 308  * when we must... :-) */
 309 long DSO_ctrl(DSO *dso, int cmd, long larg, void *parg)
 310         {
 311         if(dso == NULL)
 312                 {
 313                 DSOerr(DSO_F_DSO_CTRL,ERR_R_PASSED_NULL_PARAMETER);
 314                 return(-1);
 315                 }
 316         /* We should intercept certain generic commands and only pass control
 317          * to the method-specific ctrl() function if it's something we don't
 318          * handle. */
 319         switch(cmd)
 320                 {
 321         case DSO_CTRL_GET_FLAGS:
 322                 return dso->flags;
 323         case DSO_CTRL_SET_FLAGS:
 324                 dso->flags = (int)larg;
 325                 return(0);
 326         case DSO_CTRL_OR_FLAGS:
 327                 dso->flags |= (int)larg;
 328                 return(0);
 329         default:
 330                 break;
 331                 }
 332         if((dso->meth == NULL) || (dso->meth->dso_ctrl == NULL))
 333                 {
 334                 DSOerr(DSO_F_DSO_CTRL,DSO_R_UNSUPPORTED);
 335                 return(-1);
 336                 }
 337         return(dso->meth->dso_ctrl(dso,cmd,larg,parg));
 338         }
 339 
 340 int DSO_set_name_converter(DSO *dso, DSO_NAME_CONVERTER_FUNC cb,
 341                         DSO_NAME_CONVERTER_FUNC *oldcb)
 342         {
 343         if(dso == NULL)
 344                 {
 345                 DSOerr(DSO_F_DSO_SET_NAME_CONVERTER,
 346                                 ERR_R_PASSED_NULL_PARAMETER);
 347                 return(0);
 348                 }
 349         if(oldcb)
 350                 *oldcb = dso->name_converter;
 351         dso->name_converter = cb;
 352         return(1);
 353         }
 354 
 355 const char *DSO_get_filename(DSO *dso)
 356         {
 357         if(dso == NULL)
 358                 {
 359                 DSOerr(DSO_F_DSO_GET_FILENAME,ERR_R_PASSED_NULL_PARAMETER);
 360                 return(NULL);
 361                 }
 362         return(dso->filename);
 363         }
 364 
 365 int DSO_set_filename(DSO *dso, const char *filename)
 366         {
 367         char *copied;
 368 
 369         if((dso == NULL) || (filename == NULL))
 370                 {
 371                 DSOerr(DSO_F_DSO_SET_FILENAME,ERR_R_PASSED_NULL_PARAMETER);
 372                 return(0);
 373                 }
 374         if(dso->loaded_filename)
 375                 {
 376                 DSOerr(DSO_F_DSO_SET_FILENAME,DSO_R_DSO_ALREADY_LOADED);
 377                 return(0);
 378                 }
 379         /* We'll duplicate filename */
 380         copied = OPENSSL_malloc(strlen(filename) + 1);
 381         if(copied == NULL)
 382                 {
 383                 DSOerr(DSO_F_DSO_SET_FILENAME,ERR_R_MALLOC_FAILURE);
 384                 return(0);
 385                 }
 386         BUF_strlcpy(copied, filename, strlen(filename) + 1);
 387         if(dso->filename)
 388                 OPENSSL_free(dso->filename);
 389         dso->filename = copied;
 390         return(1);
 391         }
 392 
 393 char *DSO_merge(DSO *dso, const char *filespec1, const char *filespec2)
 394         {
 395         char *result = NULL;
 396 
 397         if(dso == NULL || filespec1 == NULL)
 398                 {
 399                 DSOerr(DSO_F_DSO_MERGE,ERR_R_PASSED_NULL_PARAMETER);
 400                 return(NULL);
 401                 }
 402         if((dso->flags & DSO_FLAG_NO_NAME_TRANSLATION) == 0)
 403                 {
 404                 if(dso->merger != NULL)
 405                         result = dso->merger(dso, filespec1, filespec2);
 406                 else if(dso->meth->dso_merger != NULL)
 407                         result = dso->meth->dso_merger(dso,
 408                                 filespec1, filespec2);
 409                 }
 410         return(result);
 411         }
 412 
 413 char *DSO_convert_filename(DSO *dso, const char *filename)
 414         {
 415         char *result = NULL;
 416 
 417         if(dso == NULL)
 418                 {
 419                 DSOerr(DSO_F_DSO_CONVERT_FILENAME,ERR_R_PASSED_NULL_PARAMETER);
 420                 return(NULL);
 421                 }
 422         if(filename == NULL)
 423                 filename = dso->filename;
 424         if(filename == NULL)
 425                 {
 426                 DSOerr(DSO_F_DSO_CONVERT_FILENAME,DSO_R_NO_FILENAME);
 427                 return(NULL);
 428                 }
 429         if((dso->flags & DSO_FLAG_NO_NAME_TRANSLATION) == 0)
 430                 {
 431                 if(dso->name_converter != NULL)
 432                         result = dso->name_converter(dso, filename);
 433                 else if(dso->meth->dso_name_converter != NULL)
 434                         result = dso->meth->dso_name_converter(dso, filename);
 435                 }
 436         if(result == NULL)
 437                 {
 438                 result = OPENSSL_malloc(strlen(filename) + 1);
 439                 if(result == NULL)
 440                         {
 441                         DSOerr(DSO_F_DSO_CONVERT_FILENAME,
 442                                         ERR_R_MALLOC_FAILURE);
 443                         return(NULL);
 444                         }
 445                 BUF_strlcpy(result, filename, strlen(filename) + 1);
 446                 }
 447         return(result);
 448         }
 449 
 450 const char *DSO_get_loaded_filename(DSO *dso)
 451         {
 452         if(dso == NULL)
 453                 {
 454                 DSOerr(DSO_F_DSO_GET_LOADED_FILENAME,
 455                                 ERR_R_PASSED_NULL_PARAMETER);
 456                 return(NULL);
 457                 }
 458         return(dso->loaded_filename);
 459         }
 460 
 461 int DSO_pathbyaddr(void *addr,char *path,int sz)
 462         {
 463         DSO_METHOD *meth = default_DSO_meth;
 464         if (meth == NULL) meth = DSO_METHOD_openssl();
 465         if (meth->pathbyaddr == NULL)
 466                 {
 467                 DSOerr(DSO_F_DSO_PATHBYADDR,DSO_R_UNSUPPORTED);
 468                 return -1;
 469                 }
 470         return (*meth->pathbyaddr)(addr,path,sz);
 471         }
 472 
 473 void *DSO_global_lookup(const char *name)
 474         {
 475         DSO_METHOD *meth = default_DSO_meth;
 476         if (meth == NULL) meth = DSO_METHOD_openssl();
 477         if (meth->globallookup == NULL)
 478                 {
 479                 DSOerr(DSO_F_DSO_GLOBAL_LOOKUP,DSO_R_UNSUPPORTED);
 480                 return NULL;
 481                 }
 482         return (*meth->globallookup)(name);
 483         }