2012-02-05 11:35:58 -05:00
|
|
|
/****************************************************************
|
|
|
|
* *
|
2024-07-19 11:43:27 -04:00
|
|
|
* Copyright 2009, 2012 Fidelity Information Services, Inc *
|
2012-02-05 11:35:58 -05:00
|
|
|
* *
|
|
|
|
* 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 */
|
|
|
|
|
2024-07-19 11:43:27 -04:00
|
|
|
#include <stdio.h> /* BYPASSOK -- Plugin doesn't have access to gtm_* header files */
|
|
|
|
#include <string.h> /* BYPASSOK -- see above */
|
|
|
|
#include <unistd.h> /* BYPASSOK -- see above */
|
|
|
|
#include <stdlib.h> /* BYPASSOK -- see above */
|
|
|
|
#include <sys/stat.h> /* BYPASSOK -- see above */
|
2012-02-05 11:35:58 -05:00
|
|
|
#include <assert.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <gpgme.h> /* gpgme functions */
|
|
|
|
#include <gpg-error.h> /* gcry*_err_t */
|
|
|
|
#include <dlfcn.h>
|
2012-03-24 14:06:46 -04:00
|
|
|
#include <sys/mman.h>
|
2012-02-05 11:35:58 -05:00
|
|
|
#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"
|
2012-03-24 14:06:46 -04:00
|
|
|
#include "gtmcrypt_sym_ref.h"
|
2024-07-19 11:43:27 -04:00
|
|
|
#include "gtmcrypt_pk_ref.h"
|
2012-02-05 11:35:58 -05:00
|
|
|
|
2024-07-19 11:43:27 -04:00
|
|
|
STATICDEF char *gtm_passwd;
|
|
|
|
STATICDEF char *gtm_passwd_env;
|
|
|
|
GBLDEF int can_prompt_passwd;
|
|
|
|
GBLDEF gpgme_ctx_t pk_crypt_ctx;
|
2012-02-05 11:35:58 -05:00
|
|
|
|
2012-03-24 14:06:46 -04:00
|
|
|
#ifdef __sparc /* for some reason sun does not provide a prototype */
|
|
|
|
int setenv(const char* name, const char *value, int overwrite);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Take a masked/unmasked password and convert it to the other form by doing an XOR operation via an XOR mask.
|
|
|
|
* XOR MASK:
|
|
|
|
* If the gtm_obfuscation_key exists and points to a file that has readable contents, the XOR mask is the
|
|
|
|
* SHA-512 hash of the contents of that file.
|
|
|
|
* Otherwise, within a pre-zero'ed buffer the length of the password the contents of the USER environment
|
|
|
|
* variable is left-justified and the decimal representation of the inode of the mumps executable is
|
|
|
|
* right-justified. The XOR mask is the SHA-512 hash of the contents of that buffer.
|
|
|
|
* <PASSWORDLEN>
|
|
|
|
* USER0000INODE ---SHA-512--> XOR mask
|
2012-02-05 11:35:58 -05:00
|
|
|
* MASKING:
|
2012-03-24 14:06:46 -04:00
|
|
|
* The original password value is XOR'ed with the XOR mask, converted to it's hex representation (for easy
|
|
|
|
* viewing) and set into the gtm_passwd environment variable. This can then be used by job'ed off child
|
|
|
|
* processes.
|
2012-02-05 11:35:58 -05:00
|
|
|
* UNMASKING:
|
2012-03-24 14:06:46 -04:00
|
|
|
* The contents of the gtm_passwd environment variable converted into its binary representation (from its
|
|
|
|
* hex representation). This gtm_passwd value is then XOR'ed with the XOR mask.
|
|
|
|
*/
|
2012-02-05 11:35:58 -05:00
|
|
|
|
|
|
|
int gc_pk_mask_unmask_passwd(char *in, char *out, int len)
|
|
|
|
{
|
2012-03-24 14:06:46 -04:00
|
|
|
char tmp[GTM_PASSPHRASE_MAX], mumps_ex[GTM_PATH_MAX], tobehashed[GTM_PASSPHRASE_MAX], hash[GTMCRYPT_HASH_LEN];
|
2024-07-19 11:43:27 -04:00
|
|
|
char *ptr, *mmap_addrs;
|
|
|
|
int passwd_len, ilen, status, i, save_errno, fd, have_hash;
|
2012-02-05 11:35:58 -05:00
|
|
|
struct stat stat_info;
|
|
|
|
|
2012-03-24 14:06:46 -04:00
|
|
|
have_hash = FALSE;
|
2012-02-05 11:35:58 -05:00
|
|
|
passwd_len = len < GTM_PASSPHRASE_MAX ? len : GTM_PASSPHRASE_MAX;
|
2012-03-24 14:06:46 -04:00
|
|
|
|
2024-07-19 11:43:27 -04:00
|
|
|
if (ptr = getenv(GTM_OBFUSCATION_KEY))
|
2012-02-05 11:35:58 -05:00
|
|
|
{
|
2012-03-24 14:06:46 -04:00
|
|
|
fd = open(ptr, O_RDONLY);
|
2024-07-19 11:43:27 -04:00
|
|
|
if ((-1 != fd) && (-1 != fstat(fd, &stat_info)) && S_ISREG(stat_info.st_mode))
|
|
|
|
{ /* File pointed by $gtm_obfuscation_key exists and is a regular file */
|
|
|
|
mmap_addrs = mmap(0,stat_info.st_size, PROT_READ, MAP_SHARED, fd, 0);
|
|
|
|
if (MAP_FAILED != mmap_addrs)
|
|
|
|
{
|
|
|
|
# ifdef USE_OPENSSL
|
|
|
|
EVP_Digest(mmap_addrs, stat_info.st_size, (unsigned char *)hash, NULL, EVP_sha512(), NULL);
|
|
|
|
# elif defined USE_GCRYPT
|
|
|
|
GC_SYM_INIT;
|
|
|
|
gcry_md_hash_buffer(GCRY_MD_SHA512, hash, mmap_addrs, stat_info.st_size );
|
|
|
|
# endif
|
|
|
|
have_hash = TRUE;
|
|
|
|
munmap(mmap_addrs, stat_info.st_size);
|
|
|
|
}
|
|
|
|
close(fd);
|
|
|
|
}
|
2012-03-24 14:06:46 -04:00
|
|
|
}
|
|
|
|
if (!have_hash)
|
|
|
|
{
|
|
|
|
memset(tobehashed, 0, passwd_len);
|
|
|
|
memset(mumps_ex, 0, GTM_PATH_MAX);
|
2024-07-19 11:43:27 -04:00
|
|
|
if (!(ptr = getenv(USER)))
|
2012-02-05 11:35:58 -05:00
|
|
|
{
|
2024-07-19 11:43:27 -04:00
|
|
|
UPDATE_ERROR_STRING(ENV_UNDEF_ERROR, USER);
|
2012-03-24 14:06:46 -04:00
|
|
|
return GC_FAILURE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
strncpy(tobehashed, ptr, passwd_len);
|
2024-07-19 11:43:27 -04:00
|
|
|
if (!(ptr = getenv(GTM_DIST)))
|
2012-02-05 11:35:58 -05:00
|
|
|
{
|
2024-07-19 11:43:27 -04:00
|
|
|
UPDATE_ERROR_STRING(ENV_UNDEF_ERROR, GTM_DIST);
|
2012-02-05 11:35:58 -05:00
|
|
|
return GC_FAILURE;
|
|
|
|
}
|
2012-03-24 14:06:46 -04:00
|
|
|
else
|
|
|
|
{
|
2024-07-19 11:43:27 -04:00
|
|
|
SNPRINTF(mumps_ex, GTM_PATH_MAX, "%s/%s", ptr, "mumps");
|
2012-03-24 14:06:46 -04:00
|
|
|
if (0 == stat(mumps_ex, &stat_info))
|
|
|
|
{
|
2024-07-19 11:43:27 -04:00
|
|
|
SNPRINTF(tmp, GTM_PASSPHRASE_MAX, "%ld", (long) stat_info.st_ino);
|
|
|
|
ilen = (int)STRLEN(tmp);
|
2012-03-24 14:06:46 -04:00
|
|
|
if (ilen < passwd_len)
|
|
|
|
strncpy(tobehashed + (passwd_len - ilen), tmp, ilen);
|
|
|
|
else
|
|
|
|
strncpy(tobehashed, tmp, passwd_len);
|
|
|
|
} else
|
|
|
|
{
|
2024-07-19 11:43:27 -04:00
|
|
|
save_errno = errno;
|
|
|
|
UPDATE_ERROR_STRING("Cannot find MUMPS executable in %s - %s", ptr, strerror(save_errno));
|
2012-03-24 14:06:46 -04:00
|
|
|
return GC_FAILURE;
|
|
|
|
}
|
|
|
|
# ifdef USE_OPENSSL
|
|
|
|
EVP_Digest(tobehashed, passwd_len, (unsigned char *)hash, NULL, EVP_sha512(), NULL);
|
|
|
|
# elif defined USE_GCRYPT
|
|
|
|
GC_SYM_INIT;
|
|
|
|
gcry_md_hash_buffer(GCRY_MD_SHA512, hash, tobehashed, passwd_len );
|
|
|
|
# endif
|
|
|
|
have_hash = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (have_hash)
|
|
|
|
{
|
|
|
|
for (i = 0; i < passwd_len; i++)
|
|
|
|
out[i] = in[i] ^ hash[i % GTMCRYPT_HASH_LEN];
|
|
|
|
return GC_SUCCESS;
|
2012-02-05 11:35:58 -05:00
|
|
|
}
|
2012-03-24 14:06:46 -04:00
|
|
|
|
2012-02-05 11:35:58 -05:00
|
|
|
return GC_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
int gc_pk_mask_unmask_passwd_interlude(int nparm, gtm_string_t *in, gtm_string_t *out, int len)
|
|
|
|
{
|
|
|
|
out->length=len;
|
|
|
|
return gc_pk_mask_unmask_passwd(in->address, out->address, len);
|
|
|
|
}
|
|
|
|
|
|
|
|
void gc_pk_scrub_passwd()
|
|
|
|
{
|
|
|
|
/* Nullify the key strings, so that any generated cores will not contain the unencrypted keys */
|
2024-07-19 11:43:27 -04:00
|
|
|
memset(gtm_passwd, 0, STRLEN(gtm_passwd));
|
2012-02-05 11:35:58 -05:00
|
|
|
/* Free gtm_passwd and gtm_passwd_env variables */
|
|
|
|
if (NULL != gtm_passwd)
|
|
|
|
GC_FREE(gtm_passwd);
|
|
|
|
if (NULL != gtm_passwd_env)
|
|
|
|
GC_FREE(gtm_passwd_env);
|
|
|
|
/* Finally release the gpgme context */
|
|
|
|
if (NULL != pk_crypt_ctx)
|
|
|
|
gpgme_release(pk_crypt_ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Loads the GTMCI variable with the path of the gtmcrypt.tab which will be placed in gtm_dist folder at build time.
|
|
|
|
* Here we assume that the tab file be in $gtm_dist/plugin/gtmcrypt
|
|
|
|
*/
|
|
|
|
|
|
|
|
void gc_pk_crypt_load_gtmci_env()
|
|
|
|
{
|
|
|
|
const char *gtm_dist_value;
|
|
|
|
const char *gtmcrypt_tab_file = "gtmcrypt.tab"; /* Name of the tab file */
|
|
|
|
static char gtmcrypt_tab_path[TAB_NAME_MAX]; /* Needs to be in scope always */
|
|
|
|
|
2024-07-19 11:43:27 -04:00
|
|
|
gtm_dist_value = getenv(GTM_DIST);
|
2012-02-05 11:35:58 -05:00
|
|
|
assert(NULL != gtm_dist_value);
|
2024-07-19 11:43:27 -04:00
|
|
|
assert(0 != STRLEN(gtm_dist_value));
|
2012-02-05 11:35:58 -05:00
|
|
|
|
2024-07-19 11:43:27 -04:00
|
|
|
SNPRINTF(gtmcrypt_tab_path, TAB_NAME_MAX, "%s/%s/%s", gtm_dist_value, "plugin/gtmcrypt", gtmcrypt_tab_file);
|
2012-02-05 11:35:58 -05:00
|
|
|
setenv(GTMCI, gtmcrypt_tab_path, TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* The following function checks if gtm_passwd is already set. If gtm_passwd is not set in the env, it's a serious
|
|
|
|
* error condition. We return back immediately. If it's set to empty string, we prompt for passwd immediately. The
|
|
|
|
* current implementation of password prompting is done via a mumps call-in to %GETPASS.
|
|
|
|
*/
|
|
|
|
|
|
|
|
xc_status_t gc_pk_crypt_prompt_passwd_if_needed(int prompt_passwd)
|
|
|
|
{
|
2024-07-19 11:43:27 -04:00
|
|
|
const char *password_routine = "getpass"; /* Name of the mumps password routine that will be called. */
|
|
|
|
char *save_gtmci; /* Points to the value that was held in GTMCI prior to modification. */
|
|
|
|
char *lgtm_passwd, tgtm_passwd[GTM_PASSPHRASE_MAX];
|
2012-02-05 11:35:58 -05:00
|
|
|
int status, len;
|
|
|
|
gtm_int_t pass_len = GTM_PASSPHRASE_MAX;
|
|
|
|
|
|
|
|
can_prompt_passwd = prompt_passwd;
|
2024-07-19 11:43:27 -04:00
|
|
|
if (!(lgtm_passwd = getenv(GTM_PASSWD)))
|
2012-02-05 11:35:58 -05:00
|
|
|
{
|
2024-07-19 11:43:27 -04:00
|
|
|
UPDATE_ERROR_STRING(ENV_UNDEF_ERROR, GTM_PASSWD);
|
2012-02-05 11:35:58 -05:00
|
|
|
return GC_FAILURE;
|
|
|
|
}
|
|
|
|
/* If the masked password in the environment is same as we have in memory then it means that the password
|
|
|
|
* has not been changed and so the actual value in the gtm_passwd is still good to use. */
|
|
|
|
if (NULL != gtm_passwd_env && (0 == strcmp(gtm_passwd_env, lgtm_passwd)))
|
|
|
|
return GC_SUCCESS;
|
|
|
|
/* If the password is set to an appropriate value, then we know for sure it's in it's masked form. So, we unmask it
|
|
|
|
* and set it in the global variable and return to the caller. */
|
2024-07-19 11:43:27 -04:00
|
|
|
if (0 < (len = (int)STRLEN(lgtm_passwd)))
|
2012-02-05 11:35:58 -05:00
|
|
|
{
|
|
|
|
if (gtm_passwd)
|
|
|
|
GC_FREE(gtm_passwd);
|
|
|
|
GC_MALLOC(gtm_passwd, len / 2 + 1, char);
|
|
|
|
memset(gtm_passwd, 0, len / 2 + 1);
|
|
|
|
GC_UNHEX(lgtm_passwd, gtm_passwd, len);
|
|
|
|
status = gc_pk_mask_unmask_passwd(gtm_passwd, gtm_passwd, len / 2);
|
|
|
|
if (GC_SUCCESS == status)
|
|
|
|
{
|
|
|
|
/* Now that we have unmasked the gtm_passwd in the environment
|
|
|
|
* store the masked version in gtm_passwd_env so that future
|
|
|
|
* calls to this function can make use of this and return early
|
|
|
|
* if we find no change between the one in the environment and
|
|
|
|
* the one in the memory */
|
|
|
|
if (NULL != gtm_passwd_env)
|
|
|
|
GC_FREE(gtm_passwd_env);
|
2024-07-19 11:43:27 -04:00
|
|
|
GC_MALLOC(gtm_passwd_env, STRLEN(lgtm_passwd) + 1, char);
|
2012-02-05 11:35:58 -05:00
|
|
|
strcpy(gtm_passwd_env, lgtm_passwd);
|
|
|
|
}
|
|
|
|
return status;
|
|
|
|
} else if (!prompt_passwd)
|
|
|
|
{
|
|
|
|
/* If we are here, it means that the caller of the plugin library was not MUMPS (may be MUPIP, DSE and LKE).
|
|
|
|
* For the utility programs, we expect the password to be set in the environment to an appropriate masked
|
|
|
|
* form. If not, it's an error and we return the appropriate error message. */
|
2024-07-19 11:43:27 -04:00
|
|
|
UPDATE_ERROR_STRING(ENV_EMPTY_ERROR ". %s", GTM_PASSWD, "Password prompting not allowed for utilities");
|
2012-02-05 11:35:58 -05:00
|
|
|
return GC_FAILURE;
|
|
|
|
}
|
|
|
|
/* Only if the gtm_passwd is set to empty string, we prompt the user for password */
|
|
|
|
GC_MALLOC(gtm_passwd, GTM_PASSPHRASE_MAX, char);
|
|
|
|
memset(gtm_passwd, 0, GTM_PASSPHRASE_MAX);
|
|
|
|
save_gtmci = getenv(GTMCI);
|
|
|
|
gc_pk_crypt_load_gtmci_env();
|
|
|
|
status = gtm_ci_fptr(password_routine, gtm_passwd, pass_len);
|
|
|
|
if (0 != status)
|
|
|
|
{
|
2024-07-19 11:43:27 -04:00
|
|
|
gtm_zstatus_fptr(gtmcrypt_err_string, MAX_GTMCRYPT_ERR_STRLEN);
|
2012-02-05 11:35:58 -05:00
|
|
|
return GC_FAILURE;
|
|
|
|
}
|
|
|
|
/* Restore the GTMCI variable */
|
|
|
|
if (NULL != save_gtmci) /* To make sure we don't set an environment variable as NULL */
|
|
|
|
setenv(GTMCI, save_gtmci, 1);
|
|
|
|
|
|
|
|
/* After applying a minimal encryption, we set it to the environment variable */
|
2024-07-19 11:43:27 -04:00
|
|
|
GC_MALLOC(lgtm_passwd, STRLEN(gtm_passwd) * 2 + 1, char);
|
|
|
|
gc_pk_mask_unmask_passwd(gtm_passwd, tgtm_passwd, (int)STRLEN(gtm_passwd));
|
|
|
|
GC_HEX(tgtm_passwd, lgtm_passwd, STRLEN(gtm_passwd) * 2);
|
|
|
|
setenv(GTM_PASSWD, lgtm_passwd, TRUE); /* Note that we currently do not free 'gtm_passwd', even if it was
|
2012-02-05 11:35:58 -05:00
|
|
|
* allocated above, as it needs to be in the env buffer
|
|
|
|
*/
|
|
|
|
return GC_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This function is called whenever gpg needs the passphrase with which the secret key is encrypted. In this case, the passphrase
|
|
|
|
* is obtained from the ENVIRONMENT VARIABLE - $gtm_passwd or by invoking the mumps engine during the "gtmcrypt_init()".
|
|
|
|
* In either ways, it's guaranteed that when this function is called, the passphrase is already set in the global variable.
|
|
|
|
*/
|
|
|
|
int gc_pk_crypt_passphrase_callback(void *opaque, const char *uid_hint,
|
|
|
|
const char *passphrase_info, int last_was_bad,
|
|
|
|
int fd)
|
|
|
|
{
|
2012-03-24 14:06:46 -04:00
|
|
|
int write_ret;
|
2012-02-05 11:35:58 -05:00
|
|
|
assert(0 != fd);
|
|
|
|
assert(NULL != gtm_passwd);
|
|
|
|
/* This is just being cautious. We would have thrown the appropriate error message
|
|
|
|
* if gtm_passwd have been zero length'ed one.
|
|
|
|
*/
|
2024-07-19 11:43:27 -04:00
|
|
|
assert(0 != STRLEN(gtm_passwd));
|
|
|
|
write_ret = write(fd, gtm_passwd, STRLEN(gtm_passwd));
|
|
|
|
if (STRLEN(gtm_passwd) == write_ret)
|
2012-03-24 14:06:46 -04:00
|
|
|
{
|
|
|
|
write_ret = write(fd, "\n", 1);
|
|
|
|
if (1 == write_ret)
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
/* Problem with one of the writes so let gpgme know */
|
|
|
|
return -1;
|
2012-02-05 11:35:58 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Given the structure that holds the plain data, this function reads through the structure and retrieves the plain text. We
|
|
|
|
* also return the number of bytes actually read from the structure.
|
|
|
|
*/
|
|
|
|
|
2024-07-19 11:43:27 -04:00
|
|
|
int gc_pk_crypt_retrieve_plain_text(gpgme_data_t plain_data, unsigned char *plain_text)
|
2012-02-05 11:35:58 -05:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
assert(NULL != plain_text);
|
|
|
|
|
|
|
|
/* Clear the temporary buffer */
|
2024-07-19 11:43:27 -04:00
|
|
|
memset(plain_text, 0, SYMMETRIC_KEY_MAX);
|
2012-02-05 11:35:58 -05:00
|
|
|
gpgme_data_seek(plain_data, 0, SEEK_SET);
|
2024-07-19 11:43:27 -04:00
|
|
|
ret = (int)gpgme_data_read(plain_data, plain_text, SYMMETRIC_KEY_MAX);
|
2012-02-05 11:35:58 -05:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This is currently necessary to work around what seems to be a gpgme issue in not clearing the plaintext keys
|
|
|
|
* from the C stack (shows up in a core dump otherwise). When gpgme is fixed, this code can be removed.
|
|
|
|
* The size of lclarray (8K) is determined purely from experimentation on all platforms.
|
|
|
|
*/
|
|
|
|
int gc_pk_scrub_plaintext_keys_from_c_stack()
|
|
|
|
{
|
|
|
|
char lclarray[8192];
|
|
|
|
|
|
|
|
memset(lclarray, 0, SIZEOF(lclarray));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This function tries to decrypt the cipher file (the file containing the symmetric key with which the database is encrypted).
|
|
|
|
* It's assumed that the context is initialized and is set with the appropriate passphrase callback. The cipher_file
|
|
|
|
* should contain the fully qualified path of the encrypted database key file. Also, plain text is supposed to be allocated with
|
|
|
|
* sufficient space to hold the decrypted text.
|
|
|
|
*/
|
2024-07-19 11:43:27 -04:00
|
|
|
gpgme_error_t gc_pk_get_decrypted_key(const char *cipher_file, unsigned char *plain_text, int *plain_text_length)
|
2012-02-05 11:35:58 -05:00
|
|
|
{
|
|
|
|
gpgme_error_t err;
|
|
|
|
gpgme_data_t cipher_data = NULL, plain_data = NULL;
|
|
|
|
xc_status_t ret_status;
|
|
|
|
gpg_err_code_t ecode;
|
2024-07-19 11:43:27 -04:00
|
|
|
char null_buffer[SYMMETRIC_KEY_MAX];
|
2012-02-05 11:35:58 -05:00
|
|
|
|
|
|
|
assert(NULL != cipher_file);
|
|
|
|
assert(NULL != plain_text);
|
|
|
|
assert(NULL != pk_crypt_ctx);
|
2024-07-19 11:43:27 -04:00
|
|
|
assert(0 != STRLEN(cipher_file));
|
2012-02-05 11:35:58 -05:00
|
|
|
|
|
|
|
/* Convert the cipher content in the cipher file into
|
|
|
|
* in-memory content. This in-memory content is stored
|
|
|
|
* in gpgme_data_t structure. */
|
|
|
|
err = gpgme_data_new_from_file(&cipher_data, cipher_file, 1);
|
|
|
|
if (!err)
|
|
|
|
{
|
|
|
|
err = gpgme_data_new(&plain_data);
|
|
|
|
if (!err)
|
|
|
|
{ /* Try decrypting the cipher content with the context.
|
|
|
|
* The decrypted content will also be stored in gpgme_data_t structure.
|
|
|
|
*/
|
|
|
|
err = gpgme_op_decrypt(pk_crypt_ctx, cipher_data, plain_data);
|
|
|
|
if (!err) /* Once decrypted, the plain text has to be obtained from the plain_data structure. */
|
|
|
|
*plain_text_length = gc_pk_crypt_retrieve_plain_text(plain_data, plain_text);
|
|
|
|
gc_pk_scrub_plaintext_keys_from_c_stack();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ecode = gpgme_err_code(err);
|
|
|
|
if (0 != ecode)
|
|
|
|
{
|
|
|
|
switch(ecode)
|
|
|
|
{
|
|
|
|
case GPG_ERR_BAD_PASSPHRASE:
|
2024-07-19 11:43:27 -04:00
|
|
|
UPDATE_ERROR_STRING("Incorrect password or error while obtaining password");
|
2012-02-05 11:35:58 -05:00
|
|
|
break;
|
|
|
|
case GPG_ERR_ENOENT:
|
2024-07-19 11:43:27 -04:00
|
|
|
UPDATE_ERROR_STRING("Encryption key file %s not found", cipher_file);
|
2012-02-05 11:35:58 -05:00
|
|
|
break;
|
|
|
|
default:
|
2024-07-19 11:43:27 -04:00
|
|
|
UPDATE_ERROR_STRING("%s", gpgme_strerror(err));
|
2012-02-05 11:35:58 -05:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (NULL != plain_data)
|
|
|
|
{ /* scrub plaintext data before releasing it */
|
2024-07-19 11:43:27 -04:00
|
|
|
assert(SYMMETRIC_KEY_MAX == SIZEOF(null_buffer));
|
|
|
|
memset(null_buffer, 0, SYMMETRIC_KEY_MAX);
|
|
|
|
gpgme_data_write(plain_data, null_buffer, SYMMETRIC_KEY_MAX);
|
2012-02-05 11:35:58 -05:00
|
|
|
gpgme_data_release(plain_data);
|
|
|
|
}
|
|
|
|
if (NULL != cipher_data)
|
|
|
|
gpgme_data_release(cipher_data);
|
|
|
|
return ecode;
|
|
|
|
}
|
|
|
|
|
|
|
|
int gc_pk_gpghome_has_permissions()
|
|
|
|
{
|
2024-07-19 11:43:27 -04:00
|
|
|
char pathname[GTM_PATH_MAX], *ptr;
|
|
|
|
int gnupghome_set, perms;
|
2012-02-05 11:35:58 -05:00
|
|
|
|
|
|
|
/* See if GNUPGHOME is set in the environment */
|
2024-07-19 11:43:27 -04:00
|
|
|
if (!(ptr = getenv(GNUPGHOME)))
|
|
|
|
{ /* $GNUPGHOME is not set, use $HOME/.gnupg as the GPG home directory */
|
2012-02-05 11:35:58 -05:00
|
|
|
gnupghome_set = FALSE;
|
2024-07-19 11:43:27 -04:00
|
|
|
if (!(ptr = getenv(HOME)))
|
2012-02-05 11:35:58 -05:00
|
|
|
{
|
2024-07-19 11:43:27 -04:00
|
|
|
UPDATE_ERROR_STRING(ENV_UNDEF_ERROR, HOME);
|
2012-02-05 11:35:58 -05:00
|
|
|
return GC_FAILURE;
|
|
|
|
}
|
2024-07-19 11:43:27 -04:00
|
|
|
SNPRINTF(pathname, GTM_PATH_MAX, "%s/%s", ptr, DOT_GNUPG);
|
2012-02-05 11:35:58 -05:00
|
|
|
} else
|
|
|
|
{
|
|
|
|
gnupghome_set = TRUE;
|
2024-07-19 11:43:27 -04:00
|
|
|
strcpy(pathname, ptr);
|
2012-02-05 11:35:58 -05:00
|
|
|
}
|
2024-07-19 11:43:27 -04:00
|
|
|
if (-1 != (perms = access(pathname, R_OK | X_OK)))
|
2012-02-05 11:35:58 -05:00
|
|
|
return GC_SUCCESS;
|
2024-07-19 11:43:27 -04:00
|
|
|
else if (EACCES == errno)
|
2012-02-05 11:35:58 -05:00
|
|
|
{
|
|
|
|
if (gnupghome_set)
|
2024-07-19 11:43:27 -04:00
|
|
|
{
|
|
|
|
UPDATE_ERROR_STRING("No read permissions on $%s", GNUPGHOME);
|
|
|
|
} else
|
|
|
|
UPDATE_ERROR_STRING("No read permissions on $%s/%s", HOME, DOT_GNUPG);
|
|
|
|
} else /* some other error */
|
|
|
|
UPDATE_ERROR_STRING("Cannot stat on %s - %d", pathname, errno);
|
2012-02-05 11:35:58 -05:00
|
|
|
return GC_FAILURE;
|
|
|
|
}
|