acl/lib_tls/tls/tls_mgr.c
2014-11-19 00:25:21 +08:00

414 lines
11 KiB
C

/*++
* NAME
* tls_mgr 3
* SUMMARY
* tlsmgr client interface
* SYNOPSIS
* #include <tls_mgr.h>
*
* int tls_mgr_seed(buf, len)
* ACL_VSTRING *buf;
* int len;
*
* int tls_mgr_policy(cache_type, cachable)
* const char *cache_type;
* int *cachable;
*
* int tls_mgr_update(cache_type, cache_id, buf, len)
* const char *cache_type;
* const char *cache_id;
* const char *buf;
* ssize_t len;
*
* int tls_mgr_lookup(cache_type, cache_id, buf)
* const char *cache_type;
* const char *cache_id;
* ACL_VSTRING *buf;
*
* int tls_mgr_delete(cache_type, cache_id)
* const char *cache_type;
* const char *cache_id;
* DESCRIPTION
* These routines communicate with the tlsmgr(8) server for
* entropy and session cache management. Since these are
* non-critical services, requests are allowed to fail without
* disrupting Postfix.
*
* tls_mgr_seed() requests entropy from the tlsmgr(8)
* Pseudo Random Number Generator (PRNG) pool.
*
* tls_mgr_policy() requests the session caching policy.
*
* tls_mgr_lookup() loads the specified session from
* the specified session cache.
*
* tls_mgr_update() saves the specified session to
* the specified session cache.
*
* tls_mgr_delete() removes specified session from
* the specified session cache.
*
* Arguments
* .IP cache_type
* One of TLS_MGR_SCACHE_SMTPD, TLS_MGR_SCACHE_SMTP
* .IP cachable
* Pointer to int, set non-zero if the requested cache_type
* is enabled.
* .IP cache_id
* The session cache lookup key.
* .IP buf
* The result or input buffer.
* .IP len
* The length of the input buffer, or the amount of data requested.
* DIAGNOSTICS
* All client functions return one of the following status codes:
* .IP TLS_MGR_STAT_OK
* The request completed, and the requested operation was
* successful (for example, the requested session was found,
* or the specified session was saved or removed).
* .IP TLS_MGR_STAT_ERR
* The request completed, but the requested operation failed
* (for example, the requested object was not found or the
* specified session was not saved or removed).
* .IP TLS_MGR_STAT_FAIL
* The request could not complete (the client could not
* communicate with the tlsmgr(8) server).
* SEE ALSO
* tlsmgr(8) TLS session and PRNG management
* LICENSE
* .ad
* .fi
* The Secure Mailer license must be distributed with this software.
* AUTHOR(S)
* Wietse Venema
* IBM T.J. Watson Research
* P.O. Box 704
* Yorktown Heights, NY 10598, USA
*--*/
#include "StdAfx.h"
#ifdef USE_TLS
#include <openssl/rand.h>
#ifdef STRCASECMP_IN_STRINGS_H
#include <strings.h>
#endif
#include "../attr/attr.h"
#include "../attr/attr_clnt.h"
/* Global library. */
#include "tls_params.h"
#include "tls_mgr.h"
/* Application-specific. */
static __thread ATTR_CLNT *tls_mgr = 0;
static void free_event(void *ctx)
{
ACL_EVENT *eventp = (ACL_EVENT*) ctx;
acl_event_free(eventp);
}
/* tls_mgr_open - create client handle */
void tls_mgr_open(ACL_EVENT *eventp)
{
/*
* Sanity check.
*/
if (tls_mgr != 0) {
if (acl_msg_verbose)
acl_msg_info("tls_mgr_open: multiple initialization");
return;
}
if (eventp == NULL) {
eventp = acl_event_new_select(1, 0);
acl_pthread_atexit_add(eventp, free_event);
}
/*
* Use whatever IPC is preferred for internal use: UNIX-domain sockets or
* Solaris streams.
*/
#ifndef VAR_TLS_MGR_SERVICE
tls_mgr = attr_clnt_create(eventp, "local:" TLS_MGR_CLASS "/" TLS_MGR_SERVICE,
var_ipc_timeout, var_ipc_idle_limit,
var_ipc_ttl_limit);
if (tls_mgr == 0) {
acl_msg_warn("attr_clnt_create error, service: local:%s",
TLS_MGR_CLASS "/" TLS_MGR_SERVICE);
return;
}
#else
tls_mgr = attr_clnt_create(eventp, var_tlsmgr_service, var_ipc_timeout,
var_ipc_idle_limit, var_ipc_ttl_limit);
if (tls_mgr == 0) {
acl_msg_warn("attr_clnt_create error, service: %s", var_tlsmgr_service);
return;
}
#endif
acl_pthread_atexit_add(tls_mgr, (void (*)(void*)) attr_clnt_free);
attr_clnt_control(tls_mgr,
ATTR_CLNT_CTL_PROTO, attr_vprint, attr_vscan,
ATTR_CLNT_CTL_END);
}
/* tls_mgr_seed - request PRNG seed */
int tls_mgr_seed(ACL_VSTRING *buf, int len)
{
int status;
/*
* Create the tlsmgr client handle.
*/
if (tls_mgr == 0) {
acl_msg_warn("tls_mgr_seed: call tls_mgr_open first");
return TLS_MGR_STAT_FAIL;
}
/*
* Request seed.
*/
if (attr_clnt_request(tls_mgr,
ATTR_FLAG_NONE, /* Request attributes */
ATTR_TYPE_STR, TLS_MGR_ATTR_REQ, TLS_MGR_REQ_SEED,
ATTR_TYPE_INT, TLS_MGR_ATTR_SIZE, len,
ATTR_TYPE_END,
ATTR_FLAG_MISSING, /* Reply attributes */
ATTR_TYPE_INT, TLS_MGR_ATTR_STATUS, &status,
ATTR_TYPE_DATA, TLS_MGR_ATTR_SEED, buf,
ATTR_TYPE_END) != 2)
status = TLS_MGR_STAT_FAIL;
return (status);
}
/* tls_mgr_policy - request caching policy */
int tls_mgr_policy(const char *cache_type, int *cachable)
{
int status;
/*
* Create the tlsmgr client handle.
*/
if (tls_mgr == 0) {
if (acl_msg_verbose)
acl_msg_info("tls_mgr_policy: call tls_mgr_open first");
return TLS_MGR_STAT_FAIL;
}
/*
* Request policy.
*/
if (attr_clnt_request(tls_mgr,
ATTR_FLAG_NONE, /* Request attributes */
ATTR_TYPE_STR, TLS_MGR_ATTR_REQ, TLS_MGR_REQ_POLICY,
ATTR_TYPE_STR, TLS_MGR_ATTR_CACHE_TYPE, cache_type,
ATTR_TYPE_END,
ATTR_FLAG_MISSING, /* Reply attributes */
ATTR_TYPE_INT, TLS_MGR_ATTR_STATUS, &status,
ATTR_TYPE_INT, TLS_MGR_ATTR_CACHABLE, cachable,
ATTR_TYPE_END) != 2)
status = TLS_MGR_STAT_FAIL;
return (status);
}
/* tls_mgr_lookup - request cached session */
int tls_mgr_lookup(const char *cache_type, const char *cache_id, ACL_VSTRING *buf)
{
int status;
/*
* Create the tlsmgr client handle.
*/
if (tls_mgr == 0) {
acl_msg_warn("tls_mgr_lookup: call tls_mgr_open first");
return TLS_MGR_STAT_FAIL;
}
/*
* Send the request and receive the reply.
*/
if (attr_clnt_request(tls_mgr,
ATTR_FLAG_NONE, /* Request */
ATTR_TYPE_STR, TLS_MGR_ATTR_REQ, TLS_MGR_REQ_LOOKUP,
ATTR_TYPE_STR, TLS_MGR_ATTR_CACHE_TYPE, cache_type,
ATTR_TYPE_STR, TLS_MGR_ATTR_CACHE_ID, cache_id,
ATTR_TYPE_END,
ATTR_FLAG_MISSING, /* Reply */
ATTR_TYPE_INT, TLS_MGR_ATTR_STATUS, &status,
ATTR_TYPE_DATA, TLS_MGR_ATTR_SESSION, buf,
ATTR_TYPE_END) != 2)
status = TLS_MGR_STAT_FAIL;
return (status);
}
/* tls_mgr_update - save session to cache */
int tls_mgr_update(const char *cache_type, const char *cache_id,
const char *buf, ssize_t len)
{
int status;
/*
* Create the tlsmgr client handle.
*/
if (tls_mgr == 0) {
acl_msg_warn("tls_mgr_update: call tls_mgr_open first");
return TLS_MGR_STAT_FAIL;
}
/*
* Send the request and receive the reply.
*/
if (attr_clnt_request(tls_mgr,
ATTR_FLAG_NONE, /* Request */
ATTR_TYPE_STR, TLS_MGR_ATTR_REQ, TLS_MGR_REQ_UPDATE,
ATTR_TYPE_STR, TLS_MGR_ATTR_CACHE_TYPE, cache_type,
ATTR_TYPE_STR, TLS_MGR_ATTR_CACHE_ID, cache_id,
ATTR_TYPE_DATA, TLS_MGR_ATTR_SESSION, len, buf,
ATTR_TYPE_END,
ATTR_FLAG_MISSING, /* Reply */
ATTR_TYPE_INT, TLS_MGR_ATTR_STATUS, &status,
ATTR_TYPE_END) != 1)
status = TLS_MGR_STAT_FAIL;
return (status);
}
/* tls_mgr_delete - remove cached session */
int tls_mgr_delete(const char *cache_type, const char *cache_id)
{
int status;
/*
* Create the tlsmgr client handle.
*/
if (tls_mgr == 0) {
acl_msg_warn("tls_mgr_delete: call tls_mgr_open first");
return TLS_MGR_STAT_FAIL;
}
/*
* Send the request and receive the reply.
*/
if (attr_clnt_request(tls_mgr,
ATTR_FLAG_NONE, /* Request */
ATTR_TYPE_STR, TLS_MGR_ATTR_REQ, TLS_MGR_REQ_DELETE,
ATTR_TYPE_STR, TLS_MGR_ATTR_CACHE_TYPE, cache_type,
ATTR_TYPE_STR, TLS_MGR_ATTR_CACHE_ID, cache_id,
ATTR_TYPE_END,
ATTR_FLAG_MISSING, /* Reply */
ATTR_TYPE_INT, TLS_MGR_ATTR_STATUS, &status,
ATTR_TYPE_END) != 1)
status = TLS_MGR_STAT_FAIL;
return (status);
}
#ifdef TEST
/* System library. */
#include <stdlib.h>
/* Utility library. */
#include <argv.h>
#include <hex_code.h>
/* Global library. */
#include <config.h>
/* Application-specific. */
#define STR(x) acl_vstring_str(x)
#define LEN(x) ACL_VSTRING_LEN(x)
int main(int unused_ac, char **av)
{
ACL_VSTRING *inbuf = acl_vstring_alloc(10);
int status;
ARGV *argv = 0;
ACL_EVENT *eventp = acl_event_new_select(1, 0);
acl_msg_verbose = 3;
mail_conf_read();
acl_msg_info("using config files in %s", var_config_dir);
if (chdir(var_queue_dir) < 0)
acl_msg_fatal("chdir %s: %s", var_queue_dir, acl_last_serror());
tls_mgr_open(eventp);
while (acl_vstring_fgets_nonl(inbuf, ACL_VSTREAM_IN)) {
argv = argv_split(STR(inbuf), " \t\r\n");
if (argv->argc == 0) {
argv_free(argv);
continue;
}
#define COMMAND(argv, str, len) \
(strcasecmp(argv->argv[0], str) == 0 && argv->argc == len)
if (COMMAND(argv, "policy", 2)) {
int cachable;
status = tls_mgr_policy(argv->argv[1], &cachable);
acl_vstream_printf("status=%d cachable=%d\n", status, cachable);
} else if (COMMAND(argv, "seed", 2)) {
ACL_VSTRING *buf = acl_vstring_alloc(10);
ACL_VSTRING *hex = acl_vstring_alloc(10);
int len = atoi(argv->argv[1]);
status = tls_mgr_seed(buf, len);
hex_encode(hex, STR(buf), LEN(buf));
acl_vstream_printf("status=%d seed=%s\n", status, STR(hex));
acl_vstring_free(hex);
acl_vstring_free(buf);
} else if (COMMAND(argv, "lookup", 3)) {
ACL_VSTRING *buf = acl_vstring_alloc(10);
status = tls_mgr_lookup(argv->argv[1], argv->argv[2], buf);
acl_vstream_printf("status=%d session=%.*s\n",
status, LEN(buf), STR(buf));
acl_vstring_free(buf);
} else if (COMMAND(argv, "update", 4)) {
status = tls_mgr_update(argv->argv[1], argv->argv[2],
argv->argv[3], strlen(argv->argv[3]));
acl_vstream_printf("status=%d\n", status);
} else if (COMMAND(argv, "delete", 3)) {
status = tls_mgr_delete(argv->argv[1], argv->argv[2]);
acl_vstream_printf("status=%d\n", status);
} else {
acl_vstream_printf("usage:\n"
"seed byte_count\n"
"policy smtpd|smtp|lmtp\n"
"lookup smtpd|smtp|lmtp cache_id\n"
"update smtpd|smtp|lmtp cache_id session\n"
"delete smtpd|smtp|lmtp cache_id\n");
}
acl_vstream_fflush(ACL_VSTREAM_OUT);
argv_free(argv);
}
acl_vstring_free(inbuf);
acl_event_free(eventp);
return (0);
}
#endif /* TEST */
#endif /* USE_TLS */