/*
* COPYRIGHT (c) International Business Machines Corp. 2015-2017
*
* This program is provided under the terms of the Common Public License,
* version 1.0 (CPL-1.0). Any use, reproduction or distribution for this
* software constitutes recipient's acceptance of CPL-1.0 terms which can be
* found in the file LICENSE file or at
* https://opensource.org/licenses/cpl1.0.php
*/
#define _GNU_SOURCE
#include <errno.h>
#include <grp.h>
#include <pthread.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <time.h>
#include <unistd.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/syscall.h>
#include "pkcs11types.h"
#include "defs.h"
#include "host_defs.h"
#include "h_extern.h"
#include "trace.h"
#include "ock_syslog.h"
#ifdef SYS_gettid
#define __gettid() syscall(SYS_gettid)
#endif
pthread_mutex_t tlmtx = PTHREAD_MUTEX_INITIALIZER;
struct trace_handle_t trace;
static const char *ock_err_msg[] = {
"Malloc Failed", /*ERR_HOST_MEMORY */
"Slot Invalid", /*ERR_SLOT_ID_INVALID */
"General Error", /*ERR_GENERAL_ERROR */
"Function Failed", /*ERR_FUNCTION_FAILED */
"Bad Arguments", /*ERR_ARGUMENTS_BAD */
"No Event", /*ERR_NO_EVENT */
"Attribute Read Only", /*ERR_ATTRIBUTE_READ_ONLY */
"Attribute Sensitive", /*ERR_ATTRIBUTE_SENSITIVE */
"Attribute Type Invalid", /*ERR_ATTRIBUTE_TYPE_INVALID */
"Attribute Value Invalid", /*ERR_ATTRIBUTE_VALUE_INVALID */
"Data Invalid", /*ERR_DATA_INVALID */
"Data Length out of Range", /*ERR_DATA_LEN_RANGE */
"Device Error", /*ERR_DEVICE_ERROR */
"Device does not have Sufficient Memory", /*ERR_DEVICE_MEMORY */
"Device Removed", /*ERR_DEVICE_REMOVED */
"Encrypted Data Invalid", /*ERR_ENCRYPTED_DATA_INVALID */
"Encrypted Data Length out of Range", /*ERR_ENCRYPTED_DATA_LEN_RANGE */
"Function Cancelled", /*ERR_FUNCTION_CANCELED */
"Function Not Parallel", /*ERR_FUNCTION_NOT_PARALLEL */
"Function Not Supported", /*ERR_FUNCTION_NOT_SUPPORTED */
"Key Changed", /*ERR_KEY_CHANGED */
"Key Function Not Permitted", /*ERR_KEY_FUNCTION_NOT_PERMITTED */
"Key Handle Invalid", /*ERR_KEY_HANDLE_INVALID */
"Key Indigestible", /*ERR_KEY_INDIGESTIBLE */
"Key Needed", /*ERR_KEY_NEEDED */
"Key Not Needed", /*ERR_KEY_NOT_NEEDED */
"Key Not Wrappable", /*ERR_KEY_NOT_WRAPPABLE */
"Key Size out of Range", /*ERR_KEY_SIZE_RANGE */
"Key Type Inconsistent", /*ERR_KEY_TYPE_INCONSISTENT */
"Key Unextractable", /*ERR_KEY_UNEXTRACTABLE */
"Mechanism Invalid", /*ERR_MECHANISM_INVALID */
"Mechanism Param Invalid", /*ERR_MECHANISM_PARAM_INVALID */
"Object Handle Invalid", /*ERR_OBJECT_HANDLE_INVALID */
"Operation Active", /*ERR_OPERATION_ACTIVE */
"Operation Not Initialized", /*ERR_OPERATION_NOT_INITIALIZED */
"Pin Incorrect", /*ERR_PIN_INCORRECT */
"Pin Invalid", /*ERR_PIN_INVALID */
"Pin Length out of Range", /*ERR_PIN_LEN_RANGE */
"Pin Expired", /*ERR_PIN_EXPIRED */
"Pin Locked", /*ERR_PIN_LOCKED */
"Session Closed", /*ERR_SESSION_CLOSED */
"Session Count", /*ERR_SESSION_COUNT */
"Session Handle Invalid", /*ERR_SESSION_HANDLE_INVALID */
"Parallel Session Not Supported", /*ERR_SESSION_PARALLEL_NOT_SUPPORTED */
"Session Read Only", /*ERR_SESSION_READ_ONLY */
"Session Exists", /*ERR_SESSION_EXISTS */
"Session Read only Exists", /*ERR_SESSION_READ_ONLY_EXISTS */
"Session Read Write Exists", /*ERR_SESSION_READ_WRITE_SO_EXISTS */
"Signature Invalid", /*ERR_SIGNATURE_INVALID */
"Signature Length out of Range", /*ERR_SIGNATURE_LEN_RANGE */
"Template Incomplete", /*ERR_TEMPLATE_INCOMPLETE */
"Template Inconsistent", /*ERR_TEMPLATE_INCONSISTENT */
"Token Not Present", /*ERR_TOKEN_NOT_PRESENT */
"Token Not Recognized", /*ERR_TOKEN_NOT_RECOGNIZED */
"Token Write Protected", /*ERR_TOKEN_WRITE_PROTECTED */
"Unwrapping Key Handle Invalid", /*ERR_UNWRAPPING_KEY_HANDLE_INVALID */
"Unwrapping Key Size Range Invalid", /*ERR_UNWRAPPING_KEY_SIZE_RANGE */
"Unwrapping Key Type Inconsistent", /*ERR_UNWRAPPING_KEY_TYPE_INCONSISTENT */
"User Already Logged In", /*ERR_USER_ALREADY_LOGGED_IN */
"User Not Logged In", /*ERR_USER_NOT_LOGGED_IN */
"User PIN Not Initialized", /*ERR_USER_PIN_NOT_INITIALIZED */
"User Type Invalid", /*ERR_USER_TYPE_INVALID */
"Another User Already Logged In", /*ERR_USER_ANOTHER_ALREADY_LOGGED_IN */
"Too Many User Types", /*ERR_USER_TOO_MANY_TYPES */
"Wrapped Key Invalid", /*ERR_WRAPPED_KEY_INVALID */
"Wrapped Key Length Invalid", /*ERR_WRAPPED_KEY_LEN_RANGE */
"Wrapping Key Handle Invalid", /*ERR_WRAPPING_KEY_HANDLE_INVALID */
"Wrapping Key Size out of Range", /*ERR_WRAPPING_KEY_SIZE_RANGE */
"Wrapping Key Type Inconsistent", /*ERR_WRAPPING_KEY_TYPE_INCONSISTENT */
"Random Seed Not Supported", /*ERR_RANDOM_SEED_NOT_SUPPORTED */
"Domain Parameter Invalid", /*ERR_DOMAIN_PARAMS_INVALID */
"Buffer Too Small", /*ERR_BUFFER_TOO_SMALL */
"Saved State Invalid", /*ERR_SAVED_STATE_INVALID */
"Information Sensitive", /*ERR_INFORMATION_SENSITIVE */
"State Unsaveable", /*ERR_STATE_UNSAVEABLE */
"API not initialized", /*ERR_CRYPTOKI_NOT_INITIALIZED */
"API already Initialized", /*ERR_CRYPTOKI_ALREADY_INITIALIZED */
"Mutex Invalid", /*ERR_MUTEX_BAD */
"Mutex was not locked", /*ERR_MUTEX_NOT_LOCKED */
"Unknown error", /*ERR_MAX */
};
void set_trace(struct trace_handle_t t_handle)
{
trace.fd = t_handle.fd;
trace.level = t_handle.level;
}
void trace_finalize(void)
{
if (trace.fd)
close(trace.fd);
trace.fd = -1;
trace.level = TRACE_LEVEL_NONE;
}
CK_RV trace_initialize(void)
{
char *opt = NULL;
char *end;
long int num;
struct group *grp;
char tracefile[PATH_MAX];
/* initialize the trace values */
trace.level = TRACE_LEVEL_NONE;
trace.fd = -1;
opt = getenv("OPENCRYPTOKI_TRACE_LEVEL");
if (!opt)
return (CKR_FUNCTION_FAILED);
num = strtol(opt, &end, 10);
if (*end) {
OCK_SYSLOG(LOG_WARNING, "OPENCRYPTOKI_TRACE_LEVEL '%s' is "
"invalid. Tracing disabled.", opt);
return (CKR_FUNCTION_FAILED);
}
switch (num) {
case TRACE_LEVEL_NONE:
return CKR_OK;
case TRACE_LEVEL_ERROR:
case TRACE_LEVEL_WARNING:
case TRACE_LEVEL_INFO:
case TRACE_LEVEL_DEVEL:
#ifdef DEBUG
case TRACE_LEVEL_DEBUG:
#endif
trace.level = num;
break;
default:
OCK_SYSLOG(LOG_WARNING, "Trace level %ld is out of range. "
"Tracing disabled.", num);
return (CKR_FUNCTION_FAILED);
}
grp = getgrnam("pkcs11");
if (grp == NULL) {
OCK_SYSLOG(LOG_ERR, "getgrnam(pkcs11) failed: %s."
"Tracing is disabled.\n", strerror(errno));
goto error;
}
/* open trace file */
snprintf(tracefile, sizeof(tracefile), "/%s/%s.%d", OCK_LOGDIR,
"trace", getpid());
trace.fd = open(tracefile, O_RDWR | O_APPEND | O_CREAT,
S_IRUSR | S_IWUSR | S_IRGRP);
if (trace.fd < 0) {
OCK_SYSLOG(LOG_WARNING,
"open(%s) failed: %s. Tracing disabled.\n",
tracefile, strerror(errno));
goto error;
}
/* set pkcs11 group permission on tracefile */
if (fchown(trace.fd, -1, grp->gr_gid) == -1) {
OCK_SYSLOG(LOG_ERR, "fchown(%s,-1,pkcs11) failed: %s."
"Tracing is disabled.\n", tracefile, strerror(errno));
goto error;
}
#ifdef PACKAGE_VERSION
TRACE_INFO("**** OCK Trace level %d activated for OCK version %s ****\n",
trace.level, PACKAGE_VERSION);
#endif
return (CKR_OK);
error:
trace.level = TRACE_LEVEL_NONE;
trace.fd = -1;
return (CKR_FUNCTION_FAILED);
}
void ock_traceit(trace_level_t level, const char *file, int line,
const char *stdll_name, const char *fmt, ...)
{
va_list ap;
time_t t;
struct tm *tm;
const char *fmt_pre;
char buf[1024];
char *pbuf;
int buflen, len;
#ifdef __gettid
pid_t tid;
#endif
if (trace.fd < 0)
return;
if (level > trace.level)
return;
pbuf = buf;
buflen = sizeof(buf);
/* add the current time */
t = time(0);
tm = localtime(&t);
len = strftime(pbuf, buflen, "%m/%d/%Y %H:%M:%S ", tm);
pbuf += len;
buflen -= len;
#ifdef __gettid
/* add thread id */
tid = __gettid();
len = snprintf(pbuf, buflen, "%u ", (unsigned int) tid);
pbuf += len;
buflen -= len;
#endif
/* add file line and stdll name */
switch (level) {
case TRACE_LEVEL_ERROR:
fmt_pre = "[%s:%d %s] ERROR: ";
break;
case TRACE_LEVEL_WARNING:
fmt_pre = "[%s:%d %s] WARN: ";
break;
case TRACE_LEVEL_INFO:
fmt_pre = "[%s:%d %s] INFO: ";
break;
case TRACE_LEVEL_DEVEL:
fmt_pre = "[%s:%d %s] DEVEL: ";
break;
case TRACE_LEVEL_DEBUG:
fmt_pre = "[%s:%d %s] DEBUG: ";
break;
default: /* cannot happen */
fmt_pre = "[%s:%d %s] ERROR: ";
break;
}
snprintf(pbuf, buflen, fmt_pre, file, line, stdll_name);
/* add the format */
len = strlen(buf);
pbuf = buf + len;
buflen = sizeof(buf) - len;
va_start(ap, fmt);
vsnprintf(pbuf, buflen, fmt, ap);
va_end(ap);
/* serialize appends to the file */
pthread_mutex_lock(&tlmtx);
if (write(trace.fd, buf, strlen(buf)) == -1)
fprintf(stderr, "cannot write to trace file\n");
pthread_mutex_unlock(&tlmtx);
}
const char *ock_err(int num)
{
if (num < 0 || num > ERR_MAX)
num = ERR_MAX;
return ock_err_msg[num];
}