1 /* dso_vms.c -*- mode:C; c-file-style: "eay" -*- */
   2 /* Written by Richard Levitte (richard@levitte.org) 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 <errno.h>
  62 #include "cryptlib.h"
  63 #include <openssl/dso.h>
  64 
  65 #ifndef OPENSSL_SYS_VMS
  66 DSO_METHOD *DSO_METHOD_vms(void)
  67         {
  68         return NULL;
  69         }
  70 #else
  71 
  72 #pragma message disable DOLLARID
  73 #include <rms.h>
  74 #include <lib$routines.h>
  75 #include <stsdef.h>
  76 #include <descrip.h>
  77 #include <starlet.h>
  78 #include "vms_rms.h"
  79 
  80 /* Some compiler options may mask the declaration of "_malloc32". */
  81 #if __INITIAL_POINTER_SIZE && defined _ANSI_C_SOURCE
  82 # if __INITIAL_POINTER_SIZE == 64
  83 #  pragma pointer_size save
  84 #  pragma pointer_size 32
  85     void * _malloc32  (__size_t);
  86 #  pragma pointer_size restore
  87 # endif /* __INITIAL_POINTER_SIZE == 64 */
  88 #endif /* __INITIAL_POINTER_SIZE && defined _ANSI_C_SOURCE */
  89 
  90 
  91 #pragma message disable DOLLARID
  92 
  93 static int vms_load(DSO *dso);
  94 static int vms_unload(DSO *dso);
  95 static void *vms_bind_var(DSO *dso, const char *symname);
  96 static DSO_FUNC_TYPE vms_bind_func(DSO *dso, const char *symname);
  97 #if 0
  98 static int vms_unbind_var(DSO *dso, char *symname, void *symptr);
  99 static int vms_unbind_func(DSO *dso, char *symname, DSO_FUNC_TYPE symptr);
 100 static int vms_init(DSO *dso);
 101 static int vms_finish(DSO *dso);
 102 static long vms_ctrl(DSO *dso, int cmd, long larg, void *parg);
 103 #endif
 104 static char *vms_name_converter(DSO *dso, const char *filename);
 105 static char *vms_merger(DSO *dso, const char *filespec1,
 106         const char *filespec2);
 107 
 108 static DSO_METHOD dso_meth_vms = {
 109         "OpenSSL 'VMS' shared library method",
 110         vms_load,
 111         NULL, /* unload */
 112         vms_bind_var,
 113         vms_bind_func,
 114 /* For now, "unbind" doesn't exist */
 115 #if 0
 116         NULL, /* unbind_var */
 117         NULL, /* unbind_func */
 118 #endif
 119         NULL, /* ctrl */
 120         vms_name_converter,
 121         vms_merger,
 122         NULL, /* init */
 123         NULL  /* finish */
 124         };
 125 
 126 /* On VMS, the only "handle" is the file name.  LIB$FIND_IMAGE_SYMBOL depends
 127  * on the reference to the file name being the same for all calls regarding
 128  * one shared image, so we'll just store it in an instance of the following
 129  * structure and put a pointer to that instance in the meth_data stack.
 130  */
 131 typedef struct dso_internal_st
 132         {
 133         /* This should contain the name only, no directory,
 134          * no extension, nothing but a name. */
 135         struct dsc$descriptor_s filename_dsc;
 136         char filename[ NAMX_MAXRSS+ 1];
 137         /* This contains whatever is not in filename, if needed.
 138          * Normally not defined. */
 139         struct dsc$descriptor_s imagename_dsc;
 140         char imagename[ NAMX_MAXRSS+ 1];
 141         } DSO_VMS_INTERNAL;
 142 
 143 DSO_METHOD *DSO_METHOD_vms(void)
 144         {
 145         return(&dso_meth_vms);
 146         }
 147 
 148 static int vms_load(DSO *dso)
 149         {
 150         void *ptr = NULL;
 151         /* See applicable comments in dso_dl.c */
 152         char *filename = DSO_convert_filename(dso, NULL);
 153 
 154 /* Ensure 32-bit pointer for "p", and appropriate malloc() function. */
 155 #if __INITIAL_POINTER_SIZE == 64
 156 # define DSO_MALLOC _malloc32
 157 # pragma pointer_size save
 158 # pragma pointer_size 32
 159 #else /* __INITIAL_POINTER_SIZE == 64 */
 160 # define DSO_MALLOC OPENSSL_malloc
 161 #endif /* __INITIAL_POINTER_SIZE == 64 [else] */
 162 
 163         DSO_VMS_INTERNAL *p = NULL;
 164 
 165 #if __INITIAL_POINTER_SIZE == 64
 166 # pragma pointer_size restore
 167 #endif /* __INITIAL_POINTER_SIZE == 64 */
 168 
 169         const char *sp1, *sp2;  /* Search result */
 170 
 171         if(filename == NULL)
 172                 {
 173                 DSOerr(DSO_F_VMS_LOAD,DSO_R_NO_FILENAME);
 174                 goto err;
 175                 }
 176 
 177         /* A file specification may look like this:
 178          *
 179          *      node::dev:[dir-spec]name.type;ver
 180          *
 181          * or (for compatibility with TOPS-20):
 182          *
 183          *      node::dev:<dir-spec>name.type;ver
 184          *
 185          * and the dir-spec uses '.' as separator.  Also, a dir-spec
 186          * may consist of several parts, with mixed use of [] and <>:
 187          *
 188          *      [dir1.]<dir2>
 189          *
 190          * We need to split the file specification into the name and
 191          * the rest (both before and after the name itself).
 192          */
 193         /* Start with trying to find the end of a dir-spec, and save the
 194            position of the byte after in sp1 */
 195         sp1 = strrchr(filename, ']');
 196         sp2 = strrchr(filename, '>');
 197         if (sp1 == NULL) sp1 = sp2;
 198         if (sp2 != NULL && sp2 > sp1) sp1 = sp2;
 199         if (sp1 == NULL) sp1 = strrchr(filename, ':');
 200         if (sp1 == NULL)
 201                 sp1 = filename;
 202         else
 203                 sp1++;          /* The byte after the found character */
 204         /* Now, let's see if there's a type, and save the position in sp2 */
 205         sp2 = strchr(sp1, '.');
 206         /* If we found it, that's where we'll cut.  Otherwise, look for a
 207            version number and save the position in sp2 */
 208         if (sp2 == NULL) sp2 = strchr(sp1, ';');
 209         /* If there was still nothing to find, set sp2 to point at the end of
 210            the string */
 211         if (sp2 == NULL) sp2 = sp1 + strlen(sp1);
 212 
 213         /* Check that we won't get buffer overflows */
 214         if (sp2 - sp1 > FILENAME_MAX
 215                 || (sp1 - filename) + strlen(sp2) > FILENAME_MAX)
 216                 {
 217                 DSOerr(DSO_F_VMS_LOAD,DSO_R_FILENAME_TOO_BIG);
 218                 goto err;
 219                 }
 220 
 221         p = DSO_MALLOC(sizeof(DSO_VMS_INTERNAL));
 222         if(p == NULL)
 223                 {
 224                 DSOerr(DSO_F_VMS_LOAD,ERR_R_MALLOC_FAILURE);
 225                 goto err;
 226                 }
 227 
 228         strncpy(p->filename, sp1, sp2-sp1);
 229         p->filename[sp2-sp1] = '\0';
 230 
 231         strncpy(p->imagename, filename, sp1-filename);
 232         p->imagename[sp1-filename] = '\0';
 233         strcat(p->imagename, sp2);
 234 
 235         p->filename_dsc.dsc$w_length = strlen(p->filename);
 236         p->filename_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
 237         p->filename_dsc.dsc$b_class = DSC$K_CLASS_S;
 238         p->filename_dsc.dsc$a_pointer = p->filename;
 239         p->imagename_dsc.dsc$w_length = strlen(p->imagename);
 240         p->imagename_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
 241         p->imagename_dsc.dsc$b_class = DSC$K_CLASS_S;
 242         p->imagename_dsc.dsc$a_pointer = p->imagename;
 243 
 244         if(!sk_void_push(dso->meth_data, (char *)p))
 245                 {
 246                 DSOerr(DSO_F_VMS_LOAD,DSO_R_STACK_ERROR);
 247                 goto err;
 248                 }
 249 
 250         /* Success (for now, we lie.  We actually do not know...) */
 251         dso->loaded_filename = filename;
 252         return(1);
 253 err:
 254         /* Cleanup! */
 255         if(p != NULL)
 256                 OPENSSL_free(p);
 257         if(filename != NULL)
 258                 OPENSSL_free(filename);
 259         return(0);
 260         }
 261 
 262 /* Note that this doesn't actually unload the shared image, as there is no
 263  * such thing in VMS.  Next time it get loaded again, a new copy will
 264  * actually be loaded.
 265  */
 266 static int vms_unload(DSO *dso)
 267         {
 268         DSO_VMS_INTERNAL *p;
 269         if(dso == NULL)
 270                 {
 271                 DSOerr(DSO_F_VMS_UNLOAD,ERR_R_PASSED_NULL_PARAMETER);
 272                 return(0);
 273                 }
 274         if(sk_void_num(dso->meth_data) < 1)
 275                 return(1);
 276         p = (DSO_VMS_INTERNAL *)sk_void_pop(dso->meth_data);
 277         if(p == NULL)
 278                 {
 279                 DSOerr(DSO_F_VMS_UNLOAD,DSO_R_NULL_HANDLE);
 280                 return(0);
 281                 }
 282         /* Cleanup */
 283         OPENSSL_free(p);
 284         return(1);
 285         }
 286 
 287 /* We must do this in a separate function because of the way the exception
 288    handler works (it makes this function return */
 289 static int do_find_symbol(DSO_VMS_INTERNAL *ptr,
 290         struct dsc$descriptor_s *symname_dsc, void **sym,
 291         unsigned long flags)
 292         {
 293         /* Make sure that signals are caught and returned instead of
 294            aborting the program.  The exception handler gets unestablished
 295            automatically on return from this function.  */
 296         lib$establish(lib$sig_to_ret);
 297 
 298         if(ptr->imagename_dsc.dsc$w_length)
 299                 return lib$find_image_symbol(&ptr->filename_dsc,
 300                         symname_dsc, sym,
 301                         &ptr->imagename_dsc, flags);
 302         else
 303                 return lib$find_image_symbol(&ptr->filename_dsc,
 304                         symname_dsc, sym,
 305                         0, flags);
 306         }
 307 
 308 void vms_bind_sym(DSO *dso, const char *symname, void **sym)
 309         {
 310         DSO_VMS_INTERNAL *ptr;
 311         int status;
 312 #if 0
 313         int flags = (1<<4); /* LIB$M_FIS_MIXEDCASE, but this symbol isn't
 314                                defined in VMS older than 7.0 or so */
 315 #else
 316         int flags = 0;
 317 #endif
 318         struct dsc$descriptor_s symname_dsc;
 319 
 320 /* Arrange 32-bit pointer to (copied) string storage, if needed. */
 321 #if __INITIAL_POINTER_SIZE == 64
 322 # define SYMNAME symname_32p
 323 # pragma pointer_size save
 324 # pragma pointer_size 32
 325         char *symname_32p;
 326 # pragma pointer_size restore
 327         char symname_32[ NAMX_MAXRSS+ 1];
 328 #else /* __INITIAL_POINTER_SIZE == 64 */
 329 # define SYMNAME ((char *) symname)
 330 #endif /* __INITIAL_POINTER_SIZE == 64 [else] */
 331 
 332         *sym = NULL;
 333 
 334         if((dso == NULL) || (symname == NULL))
 335                 {
 336                 DSOerr(DSO_F_VMS_BIND_SYM,ERR_R_PASSED_NULL_PARAMETER);
 337                 return;
 338                 }
 339 
 340 #if __INITIAL_POINTER_SIZE == 64
 341         /* Copy the symbol name to storage with a 32-bit pointer. */
 342         symname_32p = symname_32;
 343         strcpy( symname_32p, symname);
 344 #endif /* __INITIAL_POINTER_SIZE == 64 [else] */
 345 
 346         symname_dsc.dsc$w_length = strlen(SYMNAME);
 347         symname_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
 348         symname_dsc.dsc$b_class = DSC$K_CLASS_S;
 349         symname_dsc.dsc$a_pointer = SYMNAME;
 350 
 351         if(sk_void_num(dso->meth_data) < 1)
 352                 {
 353                 DSOerr(DSO_F_VMS_BIND_SYM,DSO_R_STACK_ERROR);
 354                 return;
 355                 }
 356         ptr = (DSO_VMS_INTERNAL *)sk_void_value(dso->meth_data,
 357                 sk_void_num(dso->meth_data) - 1);
 358         if(ptr == NULL)
 359                 {
 360                 DSOerr(DSO_F_VMS_BIND_SYM,DSO_R_NULL_HANDLE);
 361                 return;
 362                 }
 363 
 364         if(dso->flags & DSO_FLAG_UPCASE_SYMBOL) flags = 0;
 365 
 366         status = do_find_symbol(ptr, &symname_dsc, sym, flags);
 367 
 368         if(!$VMS_STATUS_SUCCESS(status))
 369                 {
 370                 unsigned short length;
 371                 char errstring[257];
 372                 struct dsc$descriptor_s errstring_dsc;
 373 
 374                 errstring_dsc.dsc$w_length = sizeof(errstring);
 375                 errstring_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
 376                 errstring_dsc.dsc$b_class = DSC$K_CLASS_S;
 377                 errstring_dsc.dsc$a_pointer = errstring;
 378 
 379                 *sym = NULL;
 380 
 381                 status = sys$getmsg(status, &length, &errstring_dsc, 1, 0);
 382 
 383                 if (!$VMS_STATUS_SUCCESS(status))
 384                         lib$signal(status); /* This is really bad.  Abort!  */
 385                 else
 386                         {
 387                         errstring[length] = '\0';
 388 
 389                         DSOerr(DSO_F_VMS_BIND_SYM,DSO_R_SYM_FAILURE);
 390                         if (ptr->imagename_dsc.dsc$w_length)
 391                                 ERR_add_error_data(9,
 392                                         "Symbol ", symname,
 393                                         " in ", ptr->filename,
 394                                         " (", ptr->imagename, ")",
 395                                         ": ", errstring);
 396                         else
 397                                 ERR_add_error_data(6,
 398                                         "Symbol ", symname,
 399                                         " in ", ptr->filename,
 400                                         ": ", errstring);
 401                         }
 402                 return;
 403                 }
 404         return;
 405         }
 406 
 407 static void *vms_bind_var(DSO *dso, const char *symname)
 408         {
 409         void *sym = 0;
 410         vms_bind_sym(dso, symname, &sym);
 411         return sym;
 412         }
 413 
 414 static DSO_FUNC_TYPE vms_bind_func(DSO *dso, const char *symname)
 415         {
 416         DSO_FUNC_TYPE sym = 0;
 417         vms_bind_sym(dso, symname, (void **)&sym);
 418         return sym;
 419         }
 420 
 421 
 422 static char *vms_merger(DSO *dso, const char *filespec1, const char *filespec2)
 423         {
 424         int status;
 425         int filespec1len, filespec2len;
 426         struct FAB fab;
 427         struct NAMX_STRUCT nam;
 428         char esa[ NAMX_MAXRSS+ 1];
 429         char *merged;
 430 
 431 /* Arrange 32-bit pointer to (copied) string storage, if needed. */
 432 #if __INITIAL_POINTER_SIZE == 64
 433 # define FILESPEC1 filespec1_32p;
 434 # define FILESPEC2 filespec2_32p;
 435 # pragma pointer_size save
 436 # pragma pointer_size 32
 437         char *filespec1_32p;
 438         char *filespec2_32p;
 439 # pragma pointer_size restore
 440         char filespec1_32[ NAMX_MAXRSS+ 1];
 441         char filespec2_32[ NAMX_MAXRSS+ 1];
 442 #else /* __INITIAL_POINTER_SIZE == 64 */
 443 # define FILESPEC1 ((char *) filespec1)
 444 # define FILESPEC2 ((char *) filespec2)
 445 #endif /* __INITIAL_POINTER_SIZE == 64 [else] */
 446 
 447         if (!filespec1) filespec1 = "";
 448         if (!filespec2) filespec2 = "";
 449         filespec1len = strlen(filespec1);
 450         filespec2len = strlen(filespec2);
 451 
 452 #if __INITIAL_POINTER_SIZE == 64
 453         /* Copy the file names to storage with a 32-bit pointer. */
 454         filespec1_32p = filespec1_32;
 455         filespec2_32p = filespec2_32;
 456         strcpy( filespec1_32p, filespec1);
 457         strcpy( filespec2_32p, filespec2);
 458 #endif /* __INITIAL_POINTER_SIZE == 64 [else] */
 459 
 460         fab = cc$rms_fab;
 461         nam = CC_RMS_NAMX;
 462 
 463         FAB_OR_NAML( fab, nam).FAB_OR_NAML_FNA = FILESPEC1;
 464         FAB_OR_NAML( fab, nam).FAB_OR_NAML_FNS = filespec1len;
 465         FAB_OR_NAML( fab, nam).FAB_OR_NAML_DNA = FILESPEC2;
 466         FAB_OR_NAML( fab, nam).FAB_OR_NAML_DNS = filespec2len;
 467         NAMX_DNA_FNA_SET( fab)
 468 
 469         nam.NAMX_ESA = esa;
 470         nam.NAMX_ESS = NAMX_MAXRSS;
 471         nam.NAMX_NOP = NAM$M_SYNCHK | NAM$M_PWD;
 472         SET_NAMX_NO_SHORT_UPCASE( nam);
 473 
 474         fab.FAB_NAMX = &nam;
 475 
 476         status = sys$parse(&fab, 0, 0);
 477 
 478         if(!$VMS_STATUS_SUCCESS(status))
 479                 {
 480                 unsigned short length;
 481                 char errstring[257];
 482                 struct dsc$descriptor_s errstring_dsc;
 483 
 484                 errstring_dsc.dsc$w_length = sizeof(errstring);
 485                 errstring_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
 486                 errstring_dsc.dsc$b_class = DSC$K_CLASS_S;
 487                 errstring_dsc.dsc$a_pointer = errstring;
 488 
 489                 status = sys$getmsg(status, &length, &errstring_dsc, 1, 0);
 490 
 491                 if (!$VMS_STATUS_SUCCESS(status))
 492                         lib$signal(status); /* This is really bad.  Abort!  */
 493                 else
 494                         {
 495                         errstring[length] = '\0';
 496 
 497                         DSOerr(DSO_F_VMS_MERGER,DSO_R_FAILURE);
 498                         ERR_add_error_data(7,
 499                                            "filespec \"", filespec1, "\", ",
 500                                            "defaults \"", filespec2, "\": ",
 501                                            errstring);
 502                         }
 503                 return(NULL);
 504                 }
 505 
 506         merged = OPENSSL_malloc( nam.NAMX_ESL+ 1);
 507         if(!merged)
 508                 goto malloc_err;
 509         strncpy( merged, nam.NAMX_ESA, nam.NAMX_ESL);
 510         merged[ nam.NAMX_ESL] = '\0';
 511         return(merged);
 512  malloc_err:
 513         DSOerr(DSO_F_VMS_MERGER,
 514                 ERR_R_MALLOC_FAILURE);
 515         }
 516 
 517 static char *vms_name_converter(DSO *dso, const char *filename)
 518         {
 519         int len = strlen(filename);
 520         char *not_translated = OPENSSL_malloc(len+1);
 521         strcpy(not_translated,filename);
 522         return(not_translated);
 523         }
 524 
 525 #endif /* OPENSSL_SYS_VMS */