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 */