예제 #1
0
파일: main.c 프로젝트: 1514louluo/acl
static void incr_string(ACL_VSTRING *vp, int len, const char* s, int debug)
{
	int   i;

	printf("max: %ld, len: %ld, cnt: %ld\r\n", (long) vp->maxlen,
		vp->vbuf.len, vp->vbuf.cnt);

	for (i = 0; i < len; i++)
		ACL_VSTRING_ADDCH(vp, 'x');

	if (s && *s)
		acl_vstring_sprintf_append(vp, "%s", s);
	else
		ACL_VSTRING_TERMINATE(vp);

	if (debug)
		printf("[%s]\r\n", acl_vstring_str(vp));

	printf("strlen: %ld, ACL_VSTRING_LEN: %ld, max: %ld\r\n",
		(long) strlen(acl_vstring_str(vp)),
		(long) ACL_VSTRING_LEN(vp), (long) vp->maxlen);

	printf("Enter any key to continue ...\r\n\r\n");
	getchar();

	ACL_VSTRING_RESET(vp);
	ACL_VSTRING_TERMINATE(vp);
}
예제 #2
0
void http_hdr_build_request(const HTTP_HDR_REQ *hdr_req, ACL_VSTRING *strbuf)
{
	ACL_ARRAY *entries;
	HTTP_HDR_ENTRY *entry;
	int   i, n;

	entries = hdr_req->hdr.entry_lnk;
	n = acl_array_size(entries);

	entry = (HTTP_HDR_ENTRY *) acl_array_index(entries, 0);
#if 0
	acl_vstring_sprintf(strbuf, "%s %s\r\n", entry->name, entry->value);
#else
	acl_vstring_sprintf(strbuf, "%s %s HTTP/%d.%d\r\n", entry->name,
		acl_vstring_str(hdr_req->url_part),
		hdr_req->hdr.version.major, hdr_req->hdr.version.minor);
#endif

	for (i = 1; i < n; i++) {
		entry = (HTTP_HDR_ENTRY *) acl_array_index(entries, i);
		if (entry == NULL)
			break;
		if (entry->off)
			continue;
		acl_vstring_sprintf_append(strbuf, "%s: %s\r\n", entry->name, entry->value);
	}

	acl_vstring_strcat(strbuf, "\r\n");
}
예제 #3
0
파일: unescape.c 프로젝트: 1514louluo/acl
ACL_VSTRING *escape(ACL_VSTRING *result, const char *data, ssize_t len)
{
	int     ch;

	ACL_VSTRING_RESET(result);
	while (len-- > 0) {
		ch = *UCHAR(data++);
		if (ACL_ISASCII(ch)) {
			if (ACL_ISPRINT(ch)) {
				if (ch == '\\')
					ACL_VSTRING_ADDCH(result, ch);
				ACL_VSTRING_ADDCH(result, ch);
				continue;
			} else if (ch == '\a') {		/* \a -> audible bell */
				acl_vstring_strcat(result, "\\a");
				continue;
			} else if (ch == '\b') {		/* \b -> backspace */
				acl_vstring_strcat(result, "\\b");
				continue;
			} else if (ch == '\f') {		/* \f -> formfeed */
				acl_vstring_strcat(result, "\\f");
				continue;
			} else if (ch == '\n') {		/* \n -> newline */
				acl_vstring_strcat(result, "\\n");
				continue;
			} else if (ch == '\r') {		/* \r -> carriagereturn */
				acl_vstring_strcat(result, "\\r");
				continue;
			} else if (ch == '\t') {		/* \t -> horizontal tab */
				acl_vstring_strcat(result, "\\t");
				continue;
			} else if (ch == '\v') {		/* \v -> vertical tab */
				acl_vstring_strcat(result, "\\v");
				continue;
			}
		}
		if (ACL_ISDIGIT(*UCHAR(data)))
			acl_vstring_sprintf_append(result, "\\%03d", ch);
		else
			acl_vstring_sprintf_append(result, "\\%d", ch);
	}
	ACL_VSTRING_TERMINATE(result);
	return (result);
}
예제 #4
0
파일: name_mask.c 프로젝트: 10jschen/acl
const char *str_name_mask_opt(ACL_VSTRING *buf, const char *context,
		const NAME_MASK *table,
		int mask, int flags)
{
	const char *myname = "name_mask";
	const NAME_MASK *np;
	int     len;
	static ACL_VSTRING *my_buf = 0;
	int     delim = (flags & NAME_MASK_COMMA ? ',' :
			(flags & NAME_MASK_PIPE ? '|' : ' '));

	if (buf == 0) {
		if (my_buf == 0)
			my_buf = acl_vstring_alloc(1);
		buf = my_buf;
	}
	ACL_VSTRING_RESET(buf);

	for (np = table; mask != 0; np++) {
		if (np->name == 0) {
			if (flags & NAME_MASK_FATAL) {
				acl_msg_fatal("%s: unknown %s bit in mask: 0x%x",
						myname, context, mask);
			} else if (flags & NAME_MASK_RETURN) {
				acl_msg_warn("%s: unknown %s bit in mask: 0x%x",
						myname, context, mask);
				return (0);
			} else if (flags & NAME_MASK_NUMBER) {
				acl_vstring_sprintf_append(buf, "0x%x%c", mask, delim);
			}
			break;
		}
		if (mask & np->mask) {
			mask &= ~np->mask;
			acl_vstring_sprintf_append(buf, "%s%c", np->name, delim);
		}
	}
	if ((len = (int) ACL_VSTRING_LEN(buf)) > 0)
		acl_vstring_truncate(buf, len - 1);
	ACL_VSTRING_TERMINATE(buf);

	return (STR(buf));
}
예제 #5
0
void http_hdr_build(const HTTP_HDR *hdr, ACL_VSTRING *strbuf)
{
	ACL_ARRAY *entries;
	HTTP_HDR_ENTRY *entry;
	int   i, n;

	entries = hdr->entry_lnk;
	n = acl_array_size(entries);

	entry = (HTTP_HDR_ENTRY *) acl_array_index(entries, 0);
	acl_vstring_sprintf(strbuf, "%s %s\r\n", entry->name, entry->value);

	for (i = 1; i < n; i++) {
		entry = (HTTP_HDR_ENTRY *) acl_array_index(entries, i);
		if (entry == NULL)
			break;
		if (entry->off)
			continue;
		acl_vstring_sprintf_append(strbuf, "%s: %s\r\n", entry->name, entry->value);
	}

	acl_vstring_strcat(strbuf, "\r\n");
}
예제 #6
0
static void __add_cookie_item(ACL_HTABLE *table, const char *data)
{
/* data format: name=value */
	const char *myname = "__add_cookie_item";
	ACL_ARGV *argv = NULL;
	ACL_VSTRING *str = NULL;
	const char *name;
	char *value;
	char *ptr;
	int   i;

#undef	RETURN
#define	RETURN do {  \
	if (argv)  \
		acl_argv_free(argv);  \
	return;  \
} while(0);

#undef	TRUNC_BLANK
#define	TRUNC_BLANK(_x_) do {  \
	char *_ptr_;  \
	while(*_x_ == ' ' || *_x_ == '\t')  \
		_x_++;  \
	if (*_x_ == 0)  \
		RETURN;  \
	_ptr_ = _x_;  \
	while (*_ptr_) {  \
		if (*_ptr_ == ' ' || *_ptr_ == '\t') {  \
			*_ptr_ = 0;  \
			break;  \
		}  \
		_ptr_++;  \
	}  \
} while (0);

#undef	TRUNC_BLANK_NORETURN
#define	TRUNC_BLANK_NORETURN(_x_) do {  \
	char *_ptr_;  \
	while(*_x_ == ' ' || *_x_ == '\t')  \
		_x_++;  \
	_ptr_ = _x_;  \
	while (*_ptr_) {  \
		if (*_ptr_ == ' ' || *_ptr_ == '\t') {  \
			*_ptr_ = 0;  \
			break;  \
		}  \
		_ptr_++;  \
	}  \
} while (0);

	argv = acl_argv_split(data, "=");
	if (argv->argc < 2)   /* data: "name" or "name="*/
		RETURN;

	ptr = acl_argv_index(argv, 0);
	TRUNC_BLANK(ptr);
	name = ptr;

	/* 有些站点的COOKIE比较弱,如和讯的reg.hexun.com,COOKIE名会有重复
	 * 的情况,所以必须判断一下,不必重复存储相同名字的COOKIE值,即如果
	 * 出现重复COOKIE名,则只存储第一个,这样就避免了采用哈希方式存储的
	 * 漏内存的现象发生。--- zsx, 2008.1.8
	 */
	if (acl_htable_find(table, name) != NULL) {
		RETURN;
	}

	str = acl_vstring_alloc(256);

	for (i = 1; i < argv->argc; i++) {
		ptr = acl_argv_index(argv, i);
		if (ptr == NULL)
			break;
		TRUNC_BLANK_NORETURN(ptr);
		if (*ptr == 0)
			continue;
		if (i == 1)
			acl_vstring_sprintf_append(str, "%s", ptr);
		else
			acl_vstring_sprintf_append(str, "=%s", ptr);
	}

	/* 将真实的存储数据的区域内存引出, 同时将外包结构内存释放,
	 * POSTFIX真是个好东西:) ---zsx
	 */
	value = acl_vstring_export(str);

	if (acl_htable_enter(table, name, value) == NULL)
		acl_msg_fatal("%s, %s(%d): acl_htable_enter error=%s",
			__FILE__, myname, __LINE__, acl_last_serror());

	RETURN;
}
예제 #7
0
파일: app_log.c 프로젝트: 1514louluo/acl
static int __log_open(const char *filename, void *ctx)
{
	LOG_WRAP *h_log = (LOG_WRAP *) ctx;
	int   logme = 0;
	char *facility_name = NULL;
	E_LOG_PRIORITY_T priority = E_LOG_INFO;
	E_LOG_ACTION_T action = E_LOG_PER_DAY;
	int   flush = 1;
	size_t limit_size = 0;
	E_LOG_SYNC_ACTION_T sync_action = E_LOG_SEM_WITH_MT;
	char *sem_name = NULL; 
	char *ptr, *pname;
	ACL_ARGV *env_argv;
	ACL_VSTRING *log_buf;
	int   i;

	if (filename == NULL || *filename == 0)
		return (-1);

	acl_snprintf(h_log->filename, sizeof(h_log->filename), "%s", filename);

	/* env: facility:x, priority:x, action:x, flush:x, limit_size:x, sync_action:x, sem_name:x */

	ptr = getenv("SERVICE_ENV");
	if (ptr == NULL)
		return (-1);

	env_argv = acl_argv_split(ptr, ",\t ");
	if (env_argv == NULL)
		return (-1);
	if (env_argv->argc == 0) {
		acl_argv_free(env_argv);
		return (-1);
	}

	log_buf = acl_vstring_alloc(256);

	for (i = 0; i < env_argv->argc; i++) {
		pname = acl_argv_index(env_argv, i);
		ptr = strchr(pname, ':');
		if (ptr == NULL)
			continue;
		*ptr++ = 0;
		if (*ptr == 0)
			continue;

		if (i == 0)
			acl_vstring_sprintf(log_buf, "%s:%s", pname, ptr);
		else
			acl_vstring_sprintf_append(log_buf, ", %s:%s", pname, ptr);

		if (strcasecmp(pname, "logme") == 0) {
			if (strcasecmp(ptr, "TRUE") == 0)
				logme = 1;
		} else if (strcasecmp(pname, "facility") == 0) {
			facility_name = ptr;
		} else if (strcasecmp(pname, "priority") == 0) {
			if (strcasecmp(ptr, "E_LOG_NOLOG") == 0)
				priority = E_LOG_NOLOG;
			else if (strcasecmp(ptr, "E_LOG_EMERG") == 0)
				priority = E_LOG_EMERG;
			else if (strcasecmp(ptr, "E_LOG_ALERT") == 0)
				priority = E_LOG_ALERT;
			else if (strcasecmp(ptr, "E_LOG_CRIT") == 0)
				priority = E_LOG_CRIT;
			else if (strcasecmp(ptr, "E_LOG_ERR") == 0)
				priority = E_LOG_ERR;
			else if (strcasecmp(ptr, "E_LOG_WARNING") == 0)
				priority = E_LOG_WARNING;
			else if (strcasecmp(ptr, "E_LOG_NOTICE") == 0)
				priority = E_LOG_NOTICE;
			else if (strcasecmp(ptr, "E_LOG_INFO") == 0)
				priority = E_LOG_INFO;
			else if (strcasecmp(ptr, "E_LOG_DEBUG") == 0)
				priority = E_LOG_DEBUG;
		} else if (strcasecmp(pname, "action") == 0) {
			if (strcasecmp(ptr, "E_LOG_PER_HOUR") == 0)
				action = E_LOG_PER_HOUR;
			else if (strcasecmp(ptr, "E_LOG_PER_DAY") == 0)
				action = E_LOG_PER_DAY;
			else if (strcasecmp(ptr, "E_LOG_PER_WEEK") == 0)
				action = E_LOG_PER_WEEK;
			else if (strcasecmp(ptr, "E_LOG_PER_MONTH") == 0)
				action = E_LOG_PER_MONTH;
			else if (strcasecmp(ptr, "E_LOG_PER_YEAR") == 0)
				action = E_LOG_PER_YEAR;
			else if (strcasecmp(ptr, "E_LOG_LIMIT_SIZE") == 0)
				action = E_LOG_LIMIT_SIZE;
			else if (strcasecmp(ptr, "E_LOG_SYSLOG") == 0)
				action = E_LOG_SYSLOG;
		} else if (strcasecmp(pname, "flush") == 0) {
			if (strcasecmp(ptr, "sync_flush") == 0)
				flush = 1;
			else if (strcasecmp(ptr, "async_flush") == 0)
				flush = 0;
		} else if (strcasecmp(pname, "limit_size") == 0) {
			limit_size = atoi(ptr);
		} else if (strcasecmp(pname, "sync_action") == 0) {
			if (strcasecmp(ptr, "E_LOG_NO_SYNC") == 0)
				sync_action = E_LOG_NO_SYNC;
			else if (strcasecmp(ptr, "E_LOG_THREAD_MUTEX") == 0)
				sync_action = E_LOG_THREAD_MUTEX;
			else if (strcasecmp(ptr, "E_LOG_FILE_LOCK") == 0)
				sync_action = E_LOG_FILE_LOCK;
			else if (strcasecmp(ptr, "E_LOG_SEM_WITH_MT") == 0)
				sync_action = E_LOG_SEM_WITH_MT;
			else if (strcasecmp(ptr, "E_LOG_FILE_APPEND_WITH_MT") == 0)
				sync_action = E_LOG_FILE_APPEND_WITH_MT;
		} else if (strcasecmp(pname, "sem_name") == 0) {
			sem_name = ptr;
		}
	}


#if 0
	LC_SysLogCreate(&h_log->h_log, h_log->filename);
#endif
	if (action == E_LOG_LIMIT_SIZE) {
		if (limit_size == 0)
			limit_size = 512;  /* set default size: 512 MB */
	} else
		limit_size = 0;

	if (sync_action == E_LOG_SEM_WITH_MT) {
		if (sem_name == NULL || *sem_name == 0) {
			sem_name = acl_concatenate("/tmp/", acl_safe_basename(filename), ".sem", NULL);
		} else
			sem_name = acl_mystrdup(sem_name);
	} else if (sem_name) {
		sem_name = NULL;
	}

	h_log->h_log = e_log_new2(h_log->filename, priority, action,
			flush, limit_size, facility_name, sync_action, sem_name);

	if (sem_name)
		acl_myfree(sem_name);

	if (logme) {
		/*
		char cmd[1024], buf[512];

		snprintf(buf, sizeof(buf), "filename=%s, priority=%d, action=%d, flush=%d, "
			"limit_size=%d, facility_name=%s, sync_action=%d, sem_name=%s",
			h_log->filename, priority, action,
			flush, limit_size, facility_name, sync_action, sem_name);
		snprintf(cmd, sizeof(cmd), "echo '%s, buf(%s)' >> /tmp/test1.log", acl_vstring_str(log_buf), buf);
		system(cmd);
		*/

		e_log2(h_log->h_log, "master_env: %s", acl_vstring_str(log_buf));
	}

	e_log2(h_log->h_log, "filename=%s, priority=%d, action=%d, flush=%d, "
		"limit_size=%d, facility_name=%s, sync_action=%d, sem_name=%s",
		h_log->filename, priority, action,
		flush, limit_size, facility_name, sync_action, sem_name);
		
	if (log_buf)
		acl_vstring_free(log_buf);

	return (0);
}
예제 #8
0
파일: tls_client.c 프로젝트: 1514louluo/acl
/*
 * This is the actual startup routine for the connection. We expect that the
 * buffers are flushed and the "220 Ready to start TLS" was received by us,
 * so that we can immediately start the TLS handshake process.
 */
TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props)
{
    const   char *myname = "tls_client_start";
    int     sts;
    int     protomask;
    const char *cipher_list;
    SSL_SESSION *session;
    SSL_CIPHER *cipher;
    X509   *peercert;
    TLS_SESS_STATE *TLScontext;
    TLS_APPL_STATE *app_ctx = props->ctx;
    ACL_VSTRING *myserverid;

    if (props->log_level >= 1)
	acl_msg_info("%s(%d): setting up TLS connection to %s",
		myname, __LINE__, props->namaddr);

    /*
     * First make sure we have valid protocol and cipher parameters
     * 
     * The cipherlist will be applied to the global SSL context, where it can be
     * repeatedly reset if necessary, but the protocol restrictions will be
     * is applied to the SSL connection, because protocol restrictions in the
     * global context cannot be cleared.
     */

    /*
     * OpenSSL will ignore cached sessions that use the wrong protocol. So we
     * do not need to filter out cached sessions with the "wrong" protocol,
     * rather OpenSSL will simply negotiate a new session.
     * 
     * Still, we salt the session lookup key with the protocol list, so that
     * sessions found in the cache are always acceptable.
     */
    protomask = tls_protocol_mask(props->protocols);
    if (protomask == TLS_PROTOCOL_INVALID) {
	/* tls_protocol_mask() logs no warning. */
	acl_msg_warn("%s(%d): nameaddr: %s: Invalid TLS protocol list \"%s\": aborting TLS session",
		myname, __LINE__, props->namaddr, props->protocols);
	return (0);
    }
    myserverid = acl_vstring_alloc(100);
    acl_vstring_sprintf_append(myserverid, "%s&p=%d", props->serverid, protomask);

    /*
     * Per session cipher selection for sessions with mandatory encryption
     * 
     * By the time a TLS client is negotiating ciphers it has already offered to
     * re-use a session, it is too late to renege on the offer. So we must
     * not attempt to re-use sessions whose ciphers are too weak. We salt the
     * session lookup key with the cipher list, so that sessions found in the
     * cache are always acceptable.
     */
    cipher_list = tls_set_ciphers(app_ctx, "TLS", props->cipher_grade,
	    props->cipher_exclusions);
    if (cipher_list == 0) {
	acl_msg_warn("%s(%d): %s: %s: aborting TLS session",
		myname, __LINE__, props->namaddr, acl_vstring_str(app_ctx->why));
	acl_vstring_free(myserverid);
	return (0);
    }
    if (props->log_level >= 2)
	acl_msg_info("%s(%d): %s: TLS cipher list \"%s\"",
		myname, __LINE__, props->namaddr, cipher_list);
    acl_vstring_sprintf_append(myserverid, "&c=%s", cipher_list);

    /*
     * Allocate a new TLScontext for the new connection and get an SSL
     * structure. Add the location of TLScontext to the SSL to later retrieve
     * the information inside the tls_verify_certificate_callback().
     * 
     * If session caching was enabled when TLS was initialized, the cache type
     * is stored in the client SSL context.
     */
    TLScontext = tls_alloc_sess_context(props->log_level, props->namaddr);
    TLScontext->cache_type = app_ctx->cache_type;

    TLScontext->serverid = acl_vstring_export(myserverid);

    if ((TLScontext->con = SSL_new(app_ctx->ssl_ctx)) == NULL) {
	acl_msg_warn("%s(%d): Could not allocate 'TLScontext->con' with SSL_new()",
		myname, __LINE__);
	tls_print_errors();
	tls_free_context(TLScontext);
	return (0);
    }
    if (!SSL_set_ex_data(TLScontext->con, TLScontext_index, TLScontext)) {
	acl_msg_warn("%s(%d): Could not set application data for 'TLScontext->con'",
		myname, __LINE__);
	tls_print_errors();
	tls_free_context(TLScontext);
	return (0);
    }

    /*
     * Apply session protocol restrictions.
     */
    if (protomask != 0)
	SSL_set_options(TLScontext->con,
		((protomask & TLS_PROTOCOL_TLSv1) ? SSL_OP_NO_TLSv1 : 0L)
		| ((protomask & TLS_PROTOCOL_SSLv3) ? SSL_OP_NO_SSLv3 : 0L)
		| ((protomask & TLS_PROTOCOL_SSLv2) ? SSL_OP_NO_SSLv2 : 0L));

    /*
     * The TLS connection is realized by a BIO_pair, so obtain the pair.
     * 
     * XXX There is no need to make internal_bio a member of the TLScontext
     * structure. It will be attached to TLScontext->con, and destroyed along
     * with it. The network_bio, however, needs to be freed explicitly.
     */
    if (!BIO_new_bio_pair(&TLScontext->internal_bio, TLS_BIO_BUFSIZE,
		&TLScontext->network_bio, TLS_BIO_BUFSIZE)) {
	acl_msg_warn("%s(%d): Could not obtain BIO_pair", myname, __LINE__);
	tls_print_errors();
	tls_free_context(TLScontext);
	return (0);
    }

    /*
     * XXX To avoid memory leaks we must always call SSL_SESSION_free() after
     * calling SSL_set_session(), regardless of whether or not the session
     * will be reused.
     */
    if (TLScontext->cache_type) {
	session = load_clnt_session(TLScontext);
	if (session) {
	    SSL_set_session(TLScontext->con, session);
	    SSL_SESSION_free(session);		/* 200411 */
#if (OPENSSL_VERSION_NUMBER < 0x00906011L) || (OPENSSL_VERSION_NUMBER == 0x00907000L)

	    /*
	     * Ugly Hack: OpenSSL before 0.9.6a does not store the verify
	     * result in sessions for the client side. We modify the session
	     * directly which is version specific, but this bug is version
	     * specific, too.
	     * 
	     * READ: 0-09-06-01-1 = 0-9-6-a-beta1: all versions before beta1
	     * have this bug, it has been fixed during development of 0.9.6a.
	     * The development version of 0.9.7 can have this bug, too. It
	     * has been fixed on 2000/11/29.
	     */
	    SSL_set_verify_result(TLScontext->con, session->verify_result);
#endif
	}
    }

    /*
     * Before really starting anything, try to seed the PRNG a little bit
     * more.
     */
    tls_int_seed();
    if (var_tls_daemon_rand_bytes > 0)
	(void) tls_ext_seed(var_tls_daemon_rand_bytes);

    /*
     * Initialize the SSL connection to connect state. This should not be
     * necessary anymore since 0.9.3, but the call is still in the library
     * and maintaining compatibility never hurts.
     */
    SSL_set_connect_state(TLScontext->con);

    /*
     * Connect the SSL connection with the Postfix side of the BIO-pair for
     * reading and writing.
     */
    SSL_set_bio(TLScontext->con, TLScontext->internal_bio, TLScontext->internal_bio);

    /*
     * If the debug level selected is high enough, all of the data is dumped:
     * 3 will dump the SSL negotiation, 4 will dump everything.
     * 
     * We do have an SSL_set_fd() and now suddenly a BIO_ routine is called?
     * Well there is a BIO below the SSL routines that is automatically
     * created for us, so we can use it for debugging purposes.
     */
    if (props->log_level >= 3)
	BIO_set_callback(SSL_get_rbio(TLScontext->con), tls_bio_dump_cb);

    /*
     * Start TLS negotiations. This process is a black box that invokes our
     * call-backs for certificate verification.
     * 
     * Error handling: If the SSL handhake fails, we print out an error message
     * and remove all TLS state concerning this session.
     */
    sts = tls_bio_connect(ACL_VSTREAM_SOCK(props->stream), props->timeout,
	    TLScontext);
    if (sts <= 0) {
	acl_msg_info("%s(%d): SSL_connect error to %s: %d",
		myname, __LINE__, props->namaddr, sts);
	tls_print_errors();
	uncache_session(app_ctx->ssl_ctx, TLScontext);
	tls_free_context(TLScontext);
	return (0);
    }
    /* Only log_level==4 dumps everything */
    if (props->log_level < 4)
	BIO_set_callback(SSL_get_rbio(TLScontext->con), 0);

    /*
     * The caller may want to know if this session was reused or if a new
     * session was negotiated.
     */
    TLScontext->session_reused = SSL_session_reused(TLScontext->con);
    if (props->log_level >= 2 && TLScontext->session_reused)
	acl_msg_info("%s(%d): %s: Reusing old session",
		myname, __LINE__, TLScontext->namaddr);

    /*
     * Do peername verification if requested and extract useful information
     * from the certificate for later use.
     */
    if ((peercert = SSL_get_peer_certificate(TLScontext->con)) != 0) {
	TLScontext->peer_status |= TLS_CERT_FLAG_PRESENT;

	/*
	 * Peer name or fingerprint verification as requested.
	 * Unconditionally set peer_CN, issuer_CN and peer_fingerprint.
	 */
	verify_extract_name(TLScontext, peercert, props);
	verify_extract_print(TLScontext, peercert, props);
	X509_free(peercert);
    } else {
	TLScontext->issuer_CN = acl_mystrdup("");
	TLScontext->peer_CN = acl_mystrdup("");
	TLScontext->peer_fingerprint = acl_mystrdup("");
    }

    /*
     * Finally, collect information about protocol and cipher for logging
     */
    TLScontext->protocol = SSL_get_version(TLScontext->con);
    cipher = SSL_get_current_cipher(TLScontext->con);
    TLScontext->cipher_name = SSL_CIPHER_get_name(cipher);
    TLScontext->cipher_usebits = SSL_CIPHER_get_bits(cipher,
	    &(TLScontext->cipher_algbits));

    /*
     * The TLS engine is active. Switch to the tls_timed_read/write()
     * functions and make the TLScontext available to those functions.
     */
    tls_stream_start(props->stream, TLScontext);

    /*
     * All the key facts in a single log entry.
     */
    if (props->log_level >= 1)
	acl_msg_info("%s(%d): %s TLS connection established to %s: %s with cipher %s "
		"(%d/%d bits)", myname, __LINE__,
		TLS_CERT_IS_MATCHED(TLScontext) ? "Verified" :
		TLS_CERT_IS_TRUSTED(TLScontext) ? "Trusted" : "Untrusted",
		props->namaddr, TLScontext->protocol, TLScontext->cipher_name,
		TLScontext->cipher_usebits, TLScontext->cipher_algbits);

    tls_int_seed();

    return (TLScontext);
}