1/* dso_vms.c */ 2/* 3 * Written by Richard Levitte (richard@levitte.org) for the OpenSSL project 4 * 2000. 5 */ 6/* ==================================================================== 7 * Copyright (c) 2000 The OpenSSL Project. All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in 18 * the documentation and/or other materials provided with the 19 * distribution. 20 * 21 * 3. All advertising materials mentioning features or use of this 22 * software must display the following acknowledgment: 23 * "This product includes software developed by the OpenSSL Project 24 * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 25 * 26 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 27 * endorse or promote products derived from this software without 28 * prior written permission. For written permission, please contact 29 * licensing@OpenSSL.org. 30 * 31 * 5. Products derived from this software may not be called "OpenSSL" 32 * nor may "OpenSSL" appear in their names without prior written 33 * permission of the OpenSSL Project. 34 * 35 * 6. Redistributions of any form whatsoever must retain the following 36 * acknowledgment: 37 * "This product includes software developed by the OpenSSL Project 38 * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 39 * 40 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 41 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 42 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 43 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 44 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 45 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 46 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 47 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 49 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 50 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 51 * OF THE POSSIBILITY OF SUCH DAMAGE. 52 * ==================================================================== 53 * 54 * This product includes cryptographic software written by Eric Young 55 * (eay@cryptsoft.com). This product includes software written by Tim 56 * Hudson (tjh@cryptsoft.com). 57 * 58 */ 59 60#include <stdio.h> 61#include <string.h> 62#include <errno.h> 63#include "cryptlib.h" 64#include <openssl/dso.h> 65 66#ifndef OPENSSL_SYS_VMS 67DSO_METHOD *DSO_METHOD_vms(void) 68{ 69 return NULL; 70} 71#else 72 73# pragma message disable DOLLARID 74# include <rms.h> 75# include <lib$routines.h> 76# include <stsdef.h> 77# include <descrip.h> 78# include <starlet.h> 79# include "vms_rms.h" 80 81/* Some compiler options may mask the declaration of "_malloc32". */ 82# if __INITIAL_POINTER_SIZE && defined _ANSI_C_SOURCE 83# if __INITIAL_POINTER_SIZE == 64 84# pragma pointer_size save 85# pragma pointer_size 32 86void *_malloc32(__size_t); 87# pragma pointer_size restore 88# endif /* __INITIAL_POINTER_SIZE == 64 */ 89# endif /* __INITIAL_POINTER_SIZE && defined 90 * _ANSI_C_SOURCE */ 91 92# pragma message disable DOLLARID 93 94static int vms_load(DSO *dso); 95static int vms_unload(DSO *dso); 96static void *vms_bind_var(DSO *dso, const char *symname); 97static DSO_FUNC_TYPE vms_bind_func(DSO *dso, const char *symname); 98# if 0 99static int vms_unbind_var(DSO *dso, char *symname, void *symptr); 100static int vms_unbind_func(DSO *dso, char *symname, DSO_FUNC_TYPE symptr); 101static int vms_init(DSO *dso); 102static int vms_finish(DSO *dso); 103static long vms_ctrl(DSO *dso, int cmd, long larg, void *parg); 104# endif 105static char *vms_name_converter(DSO *dso, const char *filename); 106static char *vms_merger(DSO *dso, const char *filespec1, 107 const char *filespec2); 108 109static DSO_METHOD dso_meth_vms = { 110 "OpenSSL 'VMS' shared library method", 111 vms_load, 112 NULL, /* unload */ 113 vms_bind_var, 114 vms_bind_func, 115/* For now, "unbind" doesn't exist */ 116# if 0 117 NULL, /* unbind_var */ 118 NULL, /* unbind_func */ 119# endif 120 NULL, /* ctrl */ 121 vms_name_converter, 122 vms_merger, 123 NULL, /* init */ 124 NULL /* finish */ 125}; 126 127/* 128 * On VMS, the only "handle" is the file name. LIB$FIND_IMAGE_SYMBOL depends 129 * on the reference to the file name being the same for all calls regarding 130 * one shared image, so we'll just store it in an instance of the following 131 * structure and put a pointer to that instance in the meth_data stack. 132 */ 133typedef struct dso_internal_st { 134 /* 135 * This should contain the name only, no directory, no extension, nothing 136 * but a name. 137 */ 138 struct dsc$descriptor_s filename_dsc; 139 char filename[NAMX_MAXRSS + 1]; 140 /* 141 * This contains whatever is not in filename, if needed. Normally not 142 * defined. 143 */ 144 struct dsc$descriptor_s imagename_dsc; 145 char imagename[NAMX_MAXRSS + 1]; 146} DSO_VMS_INTERNAL; 147 148DSO_METHOD *DSO_METHOD_vms(void) 149{ 150 return (&dso_meth_vms); 151} 152 153static int vms_load(DSO *dso) 154{ 155 void *ptr = NULL; 156 /* See applicable comments in dso_dl.c */ 157 char *filename = DSO_convert_filename(dso, NULL); 158 159/* Ensure 32-bit pointer for "p", and appropriate malloc() function. */ 160# if __INITIAL_POINTER_SIZE == 64 161# define DSO_MALLOC _malloc32 162# pragma pointer_size save 163# pragma pointer_size 32 164# else /* __INITIAL_POINTER_SIZE == 64 */ 165# define DSO_MALLOC OPENSSL_malloc 166# endif /* __INITIAL_POINTER_SIZE == 64 [else] */ 167 168 DSO_VMS_INTERNAL *p = NULL; 169 170# if __INITIAL_POINTER_SIZE == 64 171# pragma pointer_size restore 172# endif /* __INITIAL_POINTER_SIZE == 64 */ 173 174 const char *sp1, *sp2; /* Search result */ 175 const char *ext = NULL; /* possible extension to add */ 176 177 if (filename == NULL) { 178 DSOerr(DSO_F_VMS_LOAD, DSO_R_NO_FILENAME); 179 goto err; 180 } 181 182 /*- 183 * A file specification may look like this: 184 * 185 * node::dev:[dir-spec]name.type;ver 186 * 187 * or (for compatibility with TOPS-20): 188 * 189 * node::dev:<dir-spec>name.type;ver 190 * 191 * and the dir-spec uses '.' as separator. Also, a dir-spec 192 * may consist of several parts, with mixed use of [] and <>: 193 * 194 * [dir1.]<dir2> 195 * 196 * We need to split the file specification into the name and 197 * the rest (both before and after the name itself). 198 */ 199 /* 200 * Start with trying to find the end of a dir-spec, and save the position 201 * of the byte after in sp1 202 */ 203 sp1 = strrchr(filename, ']'); 204 sp2 = strrchr(filename, '>'); 205 if (sp1 == NULL) 206 sp1 = sp2; 207 if (sp2 != NULL && sp2 > sp1) 208 sp1 = sp2; 209 if (sp1 == NULL) 210 sp1 = strrchr(filename, ':'); 211 if (sp1 == NULL) 212 sp1 = filename; 213 else 214 sp1++; /* The byte after the found character */ 215 /* Now, let's see if there's a type, and save the position in sp2 */ 216 sp2 = strchr(sp1, '.'); 217 /* 218 * If there is a period and the next character is a semi-colon, 219 * we need to add an extension 220 */ 221 if (sp2 != NULL && sp2[1] == ';') 222 ext = ".EXE"; 223 /* 224 * If we found it, that's where we'll cut. Otherwise, look for a version 225 * number and save the position in sp2 226 */ 227 if (sp2 == NULL) { 228 sp2 = strchr(sp1, ';'); 229 ext = ".EXE"; 230 } 231 /* 232 * If there was still nothing to find, set sp2 to point at the end of the 233 * string 234 */ 235 if (sp2 == NULL) 236 sp2 = sp1 + strlen(sp1); 237 238 /* Check that we won't get buffer overflows */ 239 if (sp2 - sp1 > FILENAME_MAX 240 || (sp1 - filename) + strlen(sp2) > FILENAME_MAX) { 241 DSOerr(DSO_F_VMS_LOAD, DSO_R_FILENAME_TOO_BIG); 242 goto err; 243 } 244 245 p = DSO_MALLOC(sizeof(DSO_VMS_INTERNAL)); 246 if (p == NULL) { 247 DSOerr(DSO_F_VMS_LOAD, ERR_R_MALLOC_FAILURE); 248 goto err; 249 } 250 251 strncpy(p->filename, sp1, sp2 - sp1); 252 p->filename[sp2 - sp1] = '\0'; 253 254 strncpy(p->imagename, filename, sp1 - filename); 255 p->imagename[sp1 - filename] = '\0'; 256 if (ext) { 257 strcat(p->imagename, ext); 258 if (*sp2 == '.') 259 sp2++; 260 } 261 strcat(p->imagename, sp2); 262 263 p->filename_dsc.dsc$w_length = strlen(p->filename); 264 p->filename_dsc.dsc$b_dtype = DSC$K_DTYPE_T; 265 p->filename_dsc.dsc$b_class = DSC$K_CLASS_S; 266 p->filename_dsc.dsc$a_pointer = p->filename; 267 p->imagename_dsc.dsc$w_length = strlen(p->imagename); 268 p->imagename_dsc.dsc$b_dtype = DSC$K_DTYPE_T; 269 p->imagename_dsc.dsc$b_class = DSC$K_CLASS_S; 270 p->imagename_dsc.dsc$a_pointer = p->imagename; 271 272 if (!sk_void_push(dso->meth_data, (char *)p)) { 273 DSOerr(DSO_F_VMS_LOAD, DSO_R_STACK_ERROR); 274 goto err; 275 } 276 277 /* Success (for now, we lie. We actually do not know...) */ 278 dso->loaded_filename = filename; 279 return (1); 280 err: 281 /* Cleanup! */ 282 if (p != NULL) 283 OPENSSL_free(p); 284 if (filename != NULL) 285 OPENSSL_free(filename); 286 return (0); 287} 288 289/* 290 * Note that this doesn't actually unload the shared image, as there is no 291 * such thing in VMS. Next time it get loaded again, a new copy will 292 * actually be loaded. 293 */ 294static int vms_unload(DSO *dso) 295{ 296 DSO_VMS_INTERNAL *p; 297 if (dso == NULL) { 298 DSOerr(DSO_F_VMS_UNLOAD, ERR_R_PASSED_NULL_PARAMETER); 299 return (0); 300 } 301 if (sk_void_num(dso->meth_data) < 1) 302 return (1); 303 p = (DSO_VMS_INTERNAL *)sk_void_pop(dso->meth_data); 304 if (p == NULL) { 305 DSOerr(DSO_F_VMS_UNLOAD, DSO_R_NULL_HANDLE); 306 return (0); 307 } 308 /* Cleanup */ 309 OPENSSL_free(p); 310 return (1); 311} 312 313/* 314 * We must do this in a separate function because of the way the exception 315 * handler works (it makes this function return 316 */ 317static int do_find_symbol(DSO_VMS_INTERNAL *ptr, 318 struct dsc$descriptor_s *symname_dsc, void **sym, 319 unsigned long flags) 320{ 321 /* 322 * Make sure that signals are caught and returned instead of aborting the 323 * program. The exception handler gets unestablished automatically on 324 * return from this function. 325 */ 326 lib$establish(lib$sig_to_ret); 327 328 if (ptr->imagename_dsc.dsc$w_length) 329 return lib$find_image_symbol(&ptr->filename_dsc, 330 symname_dsc, sym, 331 &ptr->imagename_dsc, flags); 332 else 333 return lib$find_image_symbol(&ptr->filename_dsc, 334 symname_dsc, sym, 0, flags); 335} 336 337void vms_bind_sym(DSO *dso, const char *symname, void **sym) 338{ 339 DSO_VMS_INTERNAL *ptr; 340 int status; 341# if 0 342 int flags = (1 << 4); /* LIB$M_FIS_MIXEDCASE, but this symbol isn't 343 * defined in VMS older than 7.0 or so */ 344# else 345 int flags = 0; 346# endif 347 struct dsc$descriptor_s symname_dsc; 348 349/* Arrange 32-bit pointer to (copied) string storage, if needed. */ 350# if __INITIAL_POINTER_SIZE == 64 351# define SYMNAME symname_32p 352# pragma pointer_size save 353# pragma pointer_size 32 354 char *symname_32p; 355# pragma pointer_size restore 356 char symname_32[NAMX_MAXRSS + 1]; 357# else /* __INITIAL_POINTER_SIZE == 64 */ 358# define SYMNAME ((char *) symname) 359# endif /* __INITIAL_POINTER_SIZE == 64 [else] */ 360 361 *sym = NULL; 362 363 if ((dso == NULL) || (symname == NULL)) { 364 DSOerr(DSO_F_VMS_BIND_SYM, ERR_R_PASSED_NULL_PARAMETER); 365 return; 366 } 367# if __INITIAL_POINTER_SIZE == 64 368 /* Copy the symbol name to storage with a 32-bit pointer. */ 369 symname_32p = symname_32; 370 strcpy(symname_32p, symname); 371# endif /* __INITIAL_POINTER_SIZE == 64 [else] */ 372 373 symname_dsc.dsc$w_length = strlen(SYMNAME); 374 symname_dsc.dsc$b_dtype = DSC$K_DTYPE_T; 375 symname_dsc.dsc$b_class = DSC$K_CLASS_S; 376 symname_dsc.dsc$a_pointer = SYMNAME; 377 378 if (sk_void_num(dso->meth_data) < 1) { 379 DSOerr(DSO_F_VMS_BIND_SYM, DSO_R_STACK_ERROR); 380 return; 381 } 382 ptr = (DSO_VMS_INTERNAL *)sk_void_value(dso->meth_data, 383 sk_void_num(dso->meth_data) - 1); 384 if (ptr == NULL) { 385 DSOerr(DSO_F_VMS_BIND_SYM, DSO_R_NULL_HANDLE); 386 return; 387 } 388 389 if (dso->flags & DSO_FLAG_UPCASE_SYMBOL) 390 flags = 0; 391 392 status = do_find_symbol(ptr, &symname_dsc, sym, flags); 393 394 if (!$VMS_STATUS_SUCCESS(status)) { 395 unsigned short length; 396 char errstring[257]; 397 struct dsc$descriptor_s errstring_dsc; 398 399 errstring_dsc.dsc$w_length = sizeof(errstring); 400 errstring_dsc.dsc$b_dtype = DSC$K_DTYPE_T; 401 errstring_dsc.dsc$b_class = DSC$K_CLASS_S; 402 errstring_dsc.dsc$a_pointer = errstring; 403 404 *sym = NULL; 405 406 status = sys$getmsg(status, &length, &errstring_dsc, 1, 0); 407 408 if (!$VMS_STATUS_SUCCESS(status)) 409 lib$signal(status); /* This is really bad. Abort! */ 410 else { 411 errstring[length] = '\0'; 412 413 DSOerr(DSO_F_VMS_BIND_SYM, DSO_R_SYM_FAILURE); 414 if (ptr->imagename_dsc.dsc$w_length) 415 ERR_add_error_data(9, 416 "Symbol ", symname, 417 " in ", ptr->filename, 418 " (", ptr->imagename, ")", 419 ": ", errstring); 420 else 421 ERR_add_error_data(6, 422 "Symbol ", symname, 423 " in ", ptr->filename, ": ", errstring); 424 } 425 return; 426 } 427 return; 428} 429 430static void *vms_bind_var(DSO *dso, const char *symname) 431{ 432 void *sym = 0; 433 vms_bind_sym(dso, symname, &sym); 434 return sym; 435} 436 437static DSO_FUNC_TYPE vms_bind_func(DSO *dso, const char *symname) 438{ 439 DSO_FUNC_TYPE sym = 0; 440 vms_bind_sym(dso, symname, (void **)&sym); 441 return sym; 442} 443 444static char *vms_merger(DSO *dso, const char *filespec1, 445 const char *filespec2) 446{ 447 int status; 448 int filespec1len, filespec2len; 449 struct FAB fab; 450 struct NAMX_STRUCT nam; 451 char esa[NAMX_MAXRSS + 1]; 452 char *merged; 453 454/* Arrange 32-bit pointer to (copied) string storage, if needed. */ 455# if __INITIAL_POINTER_SIZE == 64 456# define FILESPEC1 filespec1_32p; 457# define FILESPEC2 filespec2_32p; 458# pragma pointer_size save 459# pragma pointer_size 32 460 char *filespec1_32p; 461 char *filespec2_32p; 462# pragma pointer_size restore 463 char filespec1_32[NAMX_MAXRSS + 1]; 464 char filespec2_32[NAMX_MAXRSS + 1]; 465# else /* __INITIAL_POINTER_SIZE == 64 */ 466# define FILESPEC1 ((char *) filespec1) 467# define FILESPEC2 ((char *) filespec2) 468# endif /* __INITIAL_POINTER_SIZE == 64 [else] */ 469 470 if (!filespec1) 471 filespec1 = ""; 472 if (!filespec2) 473 filespec2 = ""; 474 filespec1len = strlen(filespec1); 475 filespec2len = strlen(filespec2); 476 477# if __INITIAL_POINTER_SIZE == 64 478 /* Copy the file names to storage with a 32-bit pointer. */ 479 filespec1_32p = filespec1_32; 480 filespec2_32p = filespec2_32; 481 strcpy(filespec1_32p, filespec1); 482 strcpy(filespec2_32p, filespec2); 483# endif /* __INITIAL_POINTER_SIZE == 64 [else] */ 484 485 fab = cc$rms_fab; 486 nam = CC_RMS_NAMX; 487 488 FAB_OR_NAML(fab, nam).FAB_OR_NAML_FNA = FILESPEC1; 489 FAB_OR_NAML(fab, nam).FAB_OR_NAML_FNS = filespec1len; 490 FAB_OR_NAML(fab, nam).FAB_OR_NAML_DNA = FILESPEC2; 491 FAB_OR_NAML(fab, nam).FAB_OR_NAML_DNS = filespec2len; 492 NAMX_DNA_FNA_SET(fab) 493 494 nam.NAMX_ESA = esa; 495 nam.NAMX_ESS = NAMX_MAXRSS; 496 nam.NAMX_NOP = NAM$M_SYNCHK | NAM$M_PWD; 497 SET_NAMX_NO_SHORT_UPCASE(nam); 498 499 fab.FAB_NAMX = &nam; 500 501 status = sys$parse(&fab, 0, 0); 502 503 if (!$VMS_STATUS_SUCCESS(status)) { 504 unsigned short length; 505 char errstring[257]; 506 struct dsc$descriptor_s errstring_dsc; 507 508 errstring_dsc.dsc$w_length = sizeof(errstring); 509 errstring_dsc.dsc$b_dtype = DSC$K_DTYPE_T; 510 errstring_dsc.dsc$b_class = DSC$K_CLASS_S; 511 errstring_dsc.dsc$a_pointer = errstring; 512 513 status = sys$getmsg(status, &length, &errstring_dsc, 1, 0); 514 515 if (!$VMS_STATUS_SUCCESS(status)) 516 lib$signal(status); /* This is really bad. Abort! */ 517 else { 518 errstring[length] = '\0'; 519 520 DSOerr(DSO_F_VMS_MERGER, DSO_R_FAILURE); 521 ERR_add_error_data(7, 522 "filespec \"", filespec1, "\", ", 523 "defaults \"", filespec2, "\": ", errstring); 524 } 525 return (NULL); 526 } 527 528 merged = OPENSSL_malloc(nam.NAMX_ESL + 1); 529 if (!merged) 530 goto malloc_err; 531 strncpy(merged, nam.NAMX_ESA, nam.NAMX_ESL); 532 merged[nam.NAMX_ESL] = '\0'; 533 return (merged); 534 malloc_err: 535 DSOerr(DSO_F_VMS_MERGER, ERR_R_MALLOC_FAILURE); 536} 537 538static char *vms_name_converter(DSO *dso, const char *filename) 539{ 540 int len = strlen(filename); 541 char *not_translated = OPENSSL_malloc(len + 1); 542 if (not_translated) 543 strcpy(not_translated, filename); 544 return (not_translated); 545} 546 547#endif /* OPENSSL_SYS_VMS */ 548