#include "ssl_private.h"
#include "ap_mpm.h"
#include "apr_thread_mutex.h"
char *ssl_util_vhostid(apr_pool_t *p, server_rec *s)
{
char *id;
SSLSrvConfigRec *sc;
char *host;
apr_port_t port;
host = s->server_hostname;
if (s->port != 0)
port = s->port;
else {
sc = mySrvConfig(s);
if (sc->enabled == TRUE)
port = DEFAULT_HTTPS_PORT;
else
port = DEFAULT_HTTP_PORT;
}
id = apr_psprintf(p, "%s:%lu", host, (unsigned long)port);
return id;
}
apr_file_t *ssl_util_ppopen(server_rec *s, apr_pool_t *p, const char *cmd,
const char * const *argv)
{
apr_procattr_t *procattr;
apr_proc_t *proc;
if (apr_procattr_create(&procattr, p) != APR_SUCCESS)
return NULL;
if (apr_procattr_io_set(procattr, APR_FULL_BLOCK, APR_FULL_BLOCK,
APR_FULL_BLOCK) != APR_SUCCESS)
return NULL;
if (apr_procattr_dir_set(procattr,
ap_make_dirstr_parent(p, cmd)) != APR_SUCCESS)
return NULL;
if (apr_procattr_cmdtype_set(procattr, APR_PROGRAM) != APR_SUCCESS)
return NULL;
if ((proc = (apr_proc_t *)apr_pcalloc(p, sizeof(apr_proc_t))) == NULL)
return NULL;
if (apr_proc_create(proc, cmd, argv, NULL, procattr, p) != APR_SUCCESS)
return NULL;
return proc->out;
}
void ssl_util_ppclose(server_rec *s, apr_pool_t *p, apr_file_t *fp)
{
apr_file_close(fp);
return;
}
char *ssl_util_readfilter(server_rec *s, apr_pool_t *p, const char *cmd,
const char * const *argv)
{
static char buf[MAX_STRING_LEN];
apr_file_t *fp;
apr_size_t nbytes = 1;
char c;
int k;
if ((fp = ssl_util_ppopen(s, p, cmd, argv)) == NULL)
return NULL;
for (k = 0; apr_file_read(fp, &c, &nbytes) == APR_SUCCESS
&& nbytes == 1 && (k < MAX_STRING_LEN-1) ; ) {
if (c == '\n' || c == '\r')
break;
buf[k++] = c;
}
buf[k] = NUL;
ssl_util_ppclose(s, p, fp);
return buf;
}
BOOL ssl_util_path_check(ssl_pathcheck_t pcm, const char *path, apr_pool_t *p)
{
apr_finfo_t finfo;
if (path == NULL)
return FALSE;
if (pcm & SSL_PCM_EXISTS && apr_stat(&finfo, path,
APR_FINFO_TYPE|APR_FINFO_SIZE, p) != 0)
return FALSE;
if (pcm & SSL_PCM_ISREG && finfo.filetype != APR_REG)
return FALSE;
if (pcm & SSL_PCM_ISDIR && finfo.filetype != APR_DIR)
return FALSE;
if (pcm & SSL_PCM_ISNONZERO && finfo.size <= 0)
return FALSE;
return TRUE;
}
ssl_algo_t ssl_util_algotypeof(X509 *pCert, EVP_PKEY *pKey)
{
ssl_algo_t t;
EVP_PKEY *pFreeKey = NULL;
t = SSL_ALGO_UNKNOWN;
if (pCert != NULL)
pFreeKey = pKey = X509_get_pubkey(pCert);
if (pKey != NULL) {
switch (EVP_PKEY_key_type(pKey)) {
case EVP_PKEY_RSA:
t = SSL_ALGO_RSA;
break;
case EVP_PKEY_DSA:
t = SSL_ALGO_DSA;
break;
default:
break;
}
}
#ifdef OPENSSL_VERSION_NUMBER
if (pFreeKey != NULL)
EVP_PKEY_free(pFreeKey);
#endif
return t;
}
char *ssl_util_algotypestr(ssl_algo_t t)
{
char *cp;
cp = "UNKNOWN";
switch (t) {
case SSL_ALGO_RSA:
cp = "RSA";
break;
case SSL_ALGO_DSA:
cp = "DSA";
break;
default:
break;
}
return cp;
}
unsigned char *ssl_asn1_table_set(apr_hash_t *table,
const char *key,
long int length)
{
apr_ssize_t klen = strlen(key);
ssl_asn1_t *asn1 = apr_hash_get(table, key, klen);
if (asn1) {
if (asn1->nData != length) {
free(asn1->cpData);
asn1->cpData = NULL;
}
}
else {
asn1 = malloc(sizeof(*asn1));
asn1->source_mtime = 0;
asn1->cpData = NULL;
}
asn1->nData = length;
if (!asn1->cpData) {
asn1->cpData = malloc(length);
}
apr_hash_set(table, key, klen, asn1);
return asn1->cpData;
}
ssl_asn1_t *ssl_asn1_table_get(apr_hash_t *table,
const char *key)
{
return (ssl_asn1_t *)apr_hash_get(table, key, APR_HASH_KEY_STRING);
}
void ssl_asn1_table_unset(apr_hash_t *table,
const char *key)
{
apr_ssize_t klen = strlen(key);
ssl_asn1_t *asn1 = apr_hash_get(table, key, klen);
if (!asn1) {
return;
}
if (asn1->cpData) {
free(asn1->cpData);
}
free(asn1);
apr_hash_set(table, key, klen, NULL);
}
static const char *ssl_asn1_key_types[] = {"RSA", "DSA"};
const char *ssl_asn1_keystr(int keytype)
{
if (keytype >= SSL_AIDX_MAX) {
return NULL;
}
return ssl_asn1_key_types[keytype];
}
const char *ssl_asn1_table_keyfmt(apr_pool_t *p,
const char *id,
int keytype)
{
const char *keystr = ssl_asn1_keystr(keytype);
return apr_pstrcat(p, id, ":", keystr, NULL);
}
#if APR_HAS_THREADS
static apr_thread_mutex_t **lock_cs;
static int lock_num_locks;
#ifdef HAVE_SSLC
#if SSLC_VERSION_NUMBER >= 0x2000
static int ssl_util_thr_lock(int mode, int type,
char *file, int line)
#else
static void ssl_util_thr_lock(int mode, int type,
char *file, int line)
#endif
#else
static void ssl_util_thr_lock(int mode, int type,
const char *file, int line)
#endif
{
if (type < lock_num_locks) {
if (mode & CRYPTO_LOCK) {
apr_thread_mutex_lock(lock_cs[type]);
}
else {
apr_thread_mutex_unlock(lock_cs[type]);
}
#ifdef HAVE_SSLC
#if SSLC_VERSION_NUMBER >= 0x2000
return 1;
}
else {
return -1;
#endif
#endif
}
}
struct CRYPTO_dynlock_value {
apr_pool_t *pool;
const char* file;
int line;
apr_thread_mutex_t *mutex;
};
apr_pool_t *dynlockpool = NULL;
static struct CRYPTO_dynlock_value *ssl_dyn_create_function(const char *file,
int line)
{
struct CRYPTO_dynlock_value *value;
apr_pool_t *p;
apr_status_t rv;
rv = apr_pool_create(&p, dynlockpool);
if (rv != APR_SUCCESS) {
ap_log_perror(file, line, APLOG_ERR, rv, dynlockpool,
"Failed to create subpool for dynamic lock");
return NULL;
}
ap_log_perror(file, line, APLOG_DEBUG, 0, p,
"Creating dynamic lock");
value = (struct CRYPTO_dynlock_value *)apr_palloc(p,
sizeof(struct CRYPTO_dynlock_value));
if (!value) {
ap_log_perror(file, line, APLOG_ERR, 0, p,
"Failed to allocate dynamic lock structure");
return NULL;
}
value->pool = p;
value->file = apr_pstrdup(p, file);
value->line = line;
rv = apr_thread_mutex_create(&(value->mutex), APR_THREAD_MUTEX_DEFAULT,
p);
if (rv != APR_SUCCESS) {
ap_log_perror(file, line, APLOG_ERR, rv, p,
"Failed to create thread mutex for dynamic lock");
apr_pool_destroy(p);
return NULL;
}
return value;
}
static void ssl_dyn_lock_function(int mode, struct CRYPTO_dynlock_value *l,
const char *file, int line)
{
apr_status_t rv;
if (mode & CRYPTO_LOCK) {
ap_log_perror(file, line, APLOG_DEBUG, 0, l->pool,
"Acquiring mutex %s:%d", l->file, l->line);
rv = apr_thread_mutex_lock(l->mutex);
ap_log_perror(file, line, APLOG_DEBUG, rv, l->pool,
"Mutex %s:%d acquired!", l->file, l->line);
}
else {
ap_log_perror(file, line, APLOG_DEBUG, 0, l->pool,
"Releasing mutex %s:%d", l->file, l->line);
rv = apr_thread_mutex_unlock(l->mutex);
ap_log_perror(file, line, APLOG_DEBUG, rv, l->pool,
"Mutex %s:%d released!", l->file, l->line);
}
}
static void ssl_dyn_destroy_function(struct CRYPTO_dynlock_value *l,
const char *file, int line)
{
apr_status_t rv;
ap_log_perror(file, line, APLOG_DEBUG, 0, l->pool,
"Destroying dynamic lock %s:%d", l->file, l->line);
rv = apr_thread_mutex_destroy(l->mutex);
if (rv != APR_SUCCESS) {
ap_log_perror(file, line, APLOG_ERR, rv, l->pool,
"Failed to destroy mutex for dynamic lock %s:%d",
l->file, l->line);
}
apr_pool_destroy(l->pool);
}
static unsigned long ssl_util_thr_id(void)
{
#ifdef __MVS__
struct PSA {
char unmapped[540];
unsigned long PSATOLD;
} *psaptr = 0;
return psaptr->PSATOLD;
#else
return (unsigned long) apr_os_thread_current();
#endif
}
static apr_status_t ssl_util_thread_cleanup(void *data)
{
CRYPTO_set_locking_callback(NULL);
CRYPTO_set_id_callback(NULL);
CRYPTO_set_dynlock_create_callback(NULL);
CRYPTO_set_dynlock_lock_callback(NULL);
CRYPTO_set_dynlock_destroy_callback(NULL);
dynlockpool = NULL;
return APR_SUCCESS;
}
void ssl_util_thread_setup(apr_pool_t *p)
{
int i;
lock_num_locks = CRYPTO_num_locks();
lock_cs = apr_palloc(p, lock_num_locks * sizeof(*lock_cs));
for (i = 0; i < lock_num_locks; i++) {
apr_thread_mutex_create(&(lock_cs[i]), APR_THREAD_MUTEX_DEFAULT, p);
}
CRYPTO_set_id_callback(ssl_util_thr_id);
CRYPTO_set_locking_callback(ssl_util_thr_lock);
dynlockpool = p;
CRYPTO_set_dynlock_create_callback(ssl_dyn_create_function);
CRYPTO_set_dynlock_lock_callback(ssl_dyn_lock_function);
CRYPTO_set_dynlock_destroy_callback(ssl_dyn_destroy_function);
apr_pool_cleanup_register(p, NULL, ssl_util_thread_cleanup,
apr_pool_cleanup_null);
}
#endif