/**************************************************************** * * * Copyright 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #define _FILE_OFFSET_BITS 64 /* Needed to compile gpgme client progs also with large file support */ #include #include #include #include #include #include #include #include #include /* gpgme functions */ #include /* gcry*_err_t */ #include "gtmxc_types.h" /* xc_string, xc_status_t and other callin interfaces xc_fileid */ #include "gtmcrypt_interface.h" /* Function prototypes for gtmcrypt*.* functions */ #include "gtmcrypt_ref.h" #include "gtmcrypt_dbk_ref.h" #include "gtmcrypt_pk_ref.h" #include "gtmcrypt_sym_ref.h" #ifdef __MVS__ #define GTM_DIST "gtm_dist" #define GTMSHR_IMAGENAME "libgtmshr.dll" #endif char err_string[ERR_STRLEN]; int gtmcrypt_inited = FALSE, num_entries; db_key_map *db_map_root; db_key_map **fast_lookup_entry = NULL; extern gpgme_ctx_t pk_crypt_ctx; /* ==================================================================================== */ /* Plugin API implementations */ /* ==================================================================================== */ char* gtmcrypt_strerror() { return err_string; } /* Initialize the encryption environment. Note: If any of the following macros fail, the error return happens within the macro. */ xc_status_t gc_init_interface(int prompt_passwd) { /* * zOS is special when it comes to dynamic linking. * (1). Building DLL with UNRESOLVED symbols * ========================================= * Unlike other Unix platforms, on zOS DLL cannot be built having unresolved symbols and expecting them to get resolved * by the loader. * In this particular scenario we have symbols gtm_malloc, gtm_is_file_identical, gtm_free, gtm_filename_to_id and * gtm_xcfileid_free that are part of mupip executable. * As an workaround we are using function pointers to call into the interface functions so that we don't have an link-time * errors. * At runtime we do an dlopen with NULL which returns handle to global space and dlsym sets the function pointers to point to * the correct functions at runtime. * * (2). DLSYM on symbols that are already resolved from another DLL * ================================================================ * When mumps calls into libgtmcrypt it has above mentioned symbols already resolved from libgtmshr.dll. * On zOS, when we try to DLSYM using the handle returned by DLOPEN(NULL,..), DLSYM crashes while trying to find symbols * that are already loaded from another DLL(libgtmshr.dll). * As an work around we dlopen libgtmshr.dll when called from MUMPS. */ #ifdef __MVS__ void *handle = NULL; const char *gtm_dist; char gtmshr_file[GTM_PATH_MAX]; gtm_dist = getenv(GTM_DIST); snprintf(gtmshr_file, GTM_PATH_MAX, "%s/%s", gtm_dist, GTMSHR_IMAGENAME); /* * prompt_passwd = TRUE implies plugin is invoked from MUMPS. We need to dlopen libgtmshr when invoked from MUMPS. * Please refer comment 2) above. */ if (prompt_passwd) handle = dlopen(gtmshr_file, GC_FLAGS); else handle = dlopen(NULL, GC_FLAGS); if (NULL == handle) { snprintf(err_string, ERR_STRLEN, "%s", "Unable to resolve GT.M interface functions"); return GC_FAILURE; } DLSYM_ERR_AND_EXIT(gtm_is_file_identical_fptr_t, gtm_is_file_identical_fptr, GTM_IS_FILE_IDENTICAL_FUNC); DLSYM_ERR_AND_EXIT(gtm_malloc_fptr_t, gtm_malloc_fptr, GTM_MALLOC_FUNC); DLSYM_ERR_AND_EXIT(gtm_free_fptr_t, gtm_free_fptr, GTM_FREE_FUNC); DLSYM_ERR_AND_EXIT(gtm_filename_to_id_fptr_t, gtm_filename_to_id_fptr, GTM_FILENAME_TO_ID_FUNC); DLSYM_ERR_AND_EXIT(gtm_ci_fptr_t, gtm_ci_fptr, GTM_CI_FUNC); DLSYM_ERR_AND_EXIT(gtm_zstatus_fptr_t, gtm_zstatus_fptr, GTM_ZSTATUS_FUNC); DLSYM_ERR_AND_EXIT(gtm_xcfileid_free_fptr_t, gtm_xcfileid_free_fptr, GTM_XCFILEID_FREE_FUNC); #else gtm_is_file_identical_fptr = >m_is_file_identical; gtm_malloc_fptr = >m_malloc; gtm_free_fptr = >m_free; gtm_filename_to_id_fptr = >m_filename_to_id; gtm_ci_fptr = >m_ci; gtm_zstatus_fptr = >m_zstatus; gtm_xcfileid_free_fptr = >m_xcfileid_free; #endif return GC_SUCCESS; } xc_status_t gtmcrypt_init(int prompt_passwd) { if (GC_SUCCESS != gc_init_interface(prompt_passwd)) return GC_FAILURE; GC_IF_INITED_RETURN; GC_PK_INIT; GC_PK_PROMPT_PASSWD(prompt_passwd) GC_SET_INITED; return GC_SUCCESS; } /* Note: If any of the following macros fail, the error return happens within the macro. */ xc_status_t gtmcrypt_getkey_by_name(xc_string_t *filename, gtmcrypt_key_t *handle) { xc_fileid_ptr_t fileid = NULL; db_key_map *entry; xc_status_t status = GC_SUCCESS; GC_VERIFY_INITED; *handle = INVALID_HANDLE; GC_DBK_FILENAME_TO_ID(filename, fileid); entry = gc_dbk_get_entry_by_fileid(fileid); /* If the load below failed, don't continue */ GC_DBK_RELOAD_IF_NEEDED(entry, status, fileid, NULL); if (0 == status) { entry = gc_dbk_get_entry_by_fileid(fileid); if (NULL == entry) { snprintf(err_string, ERR_STRLEN, "database file %s missing in DB keys file or does not exist", filename->address); return GC_FAILURE; } *handle = entry->index; } return status; } /* Note: If any of the following macros fail, the error return happens within the macro. */ xc_status_t gtmcrypt_getkey_by_hash(xc_string_t *hash, gtmcrypt_key_t *handle) { db_key_map *entry; xc_status_t status = GC_SUCCESS; int i, err_caused_by_gpg; char save_err[ERR_STRLEN], hex_buff[GTMCRYPT_HASH_HEX_LEN + 1]; char *gpg_msg = "Verify encrypted key file and your GNUPGHOME settings"; char *correct_key_msg = "Verify encryption key in DB keys file"; char *alert_msg; *handle = INVALID_HANDLE; GC_VERIFY_INITED; entry = gc_dbk_get_entry_by_hash(hash); /* If the load below failed, don't continue */ GC_DBK_RELOAD_IF_NEEDED(entry, status, NULL, hash->address); if (0 == status) { entry = gc_dbk_get_entry_by_hash(hash); if (NULL == entry) { /* If the lookup still failed, then verify if we have right permissions on * GNUPGHOME or $HOME/.gnupg (if GNUPGHOME is unset). If not, then the below * function will store the appropriate error message in err_string and * so we can return GC_FAILURE.*/ if (GC_SUCCESS != gc_pk_gpghome_has_permissions()) return GC_FAILURE; err_caused_by_gpg = ('\0' != err_string[0]); alert_msg = (err_caused_by_gpg ? gpg_msg : correct_key_msg); /* Save the previous error message if any */ strcpy(save_err, err_string); for (i = 0; i < GTMCRYPT_HASH_HEX_LEN; i+=2) sprintf(hex_buff + i, "%02X", (unsigned char)(hash->address[i/2])); if (err_caused_by_gpg) snprintf(err_string, ERR_STRLEN, "Expected hash - %s - %s. %s", hex_buff, save_err, alert_msg); else snprintf(err_string, ERR_STRLEN, "Expected hash - %s. %s", hex_buff, alert_msg); return GC_FAILURE; } *handle = entry->index; } return status; } /* Note: If any of the following macros fail, the error return happens within the macro. */ xc_status_t gtmcrypt_hash_gen(gtmcrypt_key_t handle, xc_string_t *hash) { db_key_map *entry; GC_VERIFY_INITED; assert(INVALID_HANDLE != handle); GC_DBK_GET_ENTRY_FROM_HANDLE(handle, entry, GC_FAILURE); gc_dbk_get_hash(entry, hash); return GC_SUCCESS; } /* Note: If any of the following macros fail, the error return happens within the macro. */ xc_status_t gtmcrypt_encode(gtmcrypt_key_t handle, xc_string_t *unencrypted_block, xc_string_t *encrypted_block) { crypt_key_t key_handle; db_key_map *entry; GC_VERIFY_INITED; assert(INVALID_HANDLE != handle); GC_DBK_GET_ENTRY_FROM_HANDLE(handle, entry, GC_FAILURE); key_handle = entry->encr_key_handle; GC_SYM_ENCODE(key_handle, unencrypted_block, encrypted_block); return GC_SUCCESS; } /* Note: If any of the following macros fail, the error return happens within the macro. */ xc_status_t gtmcrypt_decode(gtmcrypt_key_t handle, xc_string_t *encrypted_block, xc_string_t *unencrypted_block) { crypt_key_t key_handle; db_key_map *entry; GC_VERIFY_INITED; assert(INVALID_HANDLE != handle); GC_DBK_GET_ENTRY_FROM_HANDLE(handle, entry, GC_FAILURE); key_handle = entry->decr_key_handle; GC_SYM_DECODE(key_handle, encrypted_block, unencrypted_block); return GC_SUCCESS; } /* Note: If any of the following macros fail, the error return happens within the macro. */ xc_status_t gtmcrypt_close() { GC_VERIFY_INITED; gc_pk_scrub_passwd(); gc_dbk_scrub_entries(); GC_CLEAR_INITED; return GC_SUCCESS; }