Exemple #1
0
static int tlsp_eval_tls_error(TLSP_STATE *state, int err)
{
    int     ciphertext_fd = state->ciphertext_fd;

    /*
     * The ciphertext file descriptor is in non-blocking mode, meaning that
     * each SSL_accept/connect/read/write/shutdown request may return an
     * "error" indication that it needs to read or write more ciphertext. The
     * purpose of this routine is to translate those "error" indications into
     * the appropriate read/write/timeout event requests.
     */
    switch (err) {

	/*
	 * No error from SSL_read and SSL_write means that the plaintext
	 * output buffer is full and that the plaintext input buffer is
	 * empty. Stop read/write events on the ciphertext stream. Keep the
	 * timer alive as a safety mechanism for the case that the plaintext
	 * pseudothreads get stuck.
	 */
    case SSL_ERROR_NONE:
	if (state->ssl_last_err != SSL_ERROR_NONE) {
	    event_disable_readwrite(ciphertext_fd);
	    event_request_timer(tlsp_ciphertext_event, (char *) state,
				state->timeout);
	    state->ssl_last_err = SSL_ERROR_NONE;
	}
	return (0);

	/*
	 * The TLS engine wants to write to the network. Turn on
	 * write/timeout events on the ciphertext stream.
	 */
    case SSL_ERROR_WANT_WRITE:
	if (state->ssl_last_err == SSL_ERROR_WANT_READ)
	    event_disable_readwrite(ciphertext_fd);
	if (state->ssl_last_err != SSL_ERROR_WANT_WRITE) {
	    event_enable_write(ciphertext_fd, tlsp_ciphertext_event,
			       (char *) state);
	    state->ssl_last_err = SSL_ERROR_WANT_WRITE;
	}
	event_request_timer(tlsp_ciphertext_event, (char *) state,
			    state->timeout);
	return (0);

	/*
	 * The TLS engine wants to read from the network. Turn on
	 * read/timeout events on the ciphertext stream.
	 */
    case SSL_ERROR_WANT_READ:
	if (state->ssl_last_err == SSL_ERROR_WANT_WRITE)
	    event_disable_readwrite(ciphertext_fd);
	if (state->ssl_last_err != SSL_ERROR_WANT_READ) {
	    event_enable_read(ciphertext_fd, tlsp_ciphertext_event,
			      (char *) state);
	    state->ssl_last_err = SSL_ERROR_WANT_READ;
	}
	event_request_timer(tlsp_ciphertext_event, (char *) state,
			    state->timeout);
	return (0);

	/*
	 * Some error. Self-destruct. This automagically cleans up all
	 * pending read/write and timeout event requests, making state a
	 * dangling pointer.
	 */
    case SSL_ERROR_SSL:
	tls_print_errors();
	/* FALLTHROUGH */
    default:
	tlsp_state_free(state);
	return (-1);
    }
}
Exemple #2
0
static void tlsp_get_request_event(int event, char *context)
{
    const char *myname = "tlsp_get_request_event";
    TLSP_STATE *state = (TLSP_STATE *) context;
    VSTREAM *plaintext_stream = state->plaintext_stream;
    int     plaintext_fd = vstream_fileno(plaintext_stream);
    static VSTRING *remote_endpt;
    static VSTRING *server_id;
    int     req_flags;
    int     timeout;
    int     ready;

    /*
     * One-time initialization.
     */
    if (remote_endpt == 0) {
	remote_endpt = vstring_alloc(10);
	server_id = vstring_alloc(10);
    }

    /*
     * At this point we still manually manage plaintext read/write/timeout
     * events. Turn off timer events. Below we disable read events on error,
     * and redefine read events on success.
     */
    if (event != EVENT_TIME)
	event_cancel_timer(tlsp_get_request_event, (char *) state);

    /*
     * We must send some data, after receiving the request attributes and
     * before receiving the remote file descriptor. We can't assume
     * UNIX-domain socket semantics here.
     */
    if (event != EVENT_READ
	|| attr_scan(plaintext_stream, ATTR_FLAG_STRICT,
		     ATTR_TYPE_STR, MAIL_ATTR_REMOTE_ENDPT, remote_endpt,
		     ATTR_TYPE_INT, MAIL_ATTR_FLAGS, &req_flags,
		     ATTR_TYPE_INT, MAIL_ATTR_TIMEOUT, &timeout,
		     ATTR_TYPE_STR, MAIL_ATTR_SERVER_ID, server_id,
		     ATTR_TYPE_END) != 4) {
	msg_warn("%s: receive request attributes: %m", myname);
	event_disable_readwrite(plaintext_fd);
	tlsp_state_free(state);
	return;
    }

    /*
     * If the requested TLS engine is unavailable, hang up after making sure
     * that the plaintext peer has received our "sorry" indication.
     */
    ready = ((req_flags & TLS_PROXY_FLAG_ROLE_SERVER) != 0
	     && tlsp_server_ctx != 0);
    if (attr_print(plaintext_stream, ATTR_FLAG_NONE,
		   ATTR_TYPE_INT, MAIL_ATTR_STATUS, ready,
		   ATTR_TYPE_END) != 0
	|| vstream_fflush(plaintext_stream) != 0
	|| ready == 0) {
	read_wait(plaintext_fd, TLSP_INIT_TIMEOUT);	/* XXX */
	event_disable_readwrite(plaintext_fd);
	tlsp_state_free(state);
	return;
    }

    /*
     * XXX We use the same fixed timeout throughout the entire session for
     * both plaintext and ciphertext communication. This timeout is just a
     * safety feature; the real timeout will be enforced by our plaintext
     * peer.
     */
    else {
	state->remote_endpt = mystrdup(STR(remote_endpt));
	state->server_id = mystrdup(STR(server_id));
	msg_info("CONNECT %s %s",
		 (req_flags & TLS_PROXY_FLAG_ROLE_SERVER) ? "from" :
		 (req_flags & TLS_PROXY_FLAG_ROLE_CLIENT) ? "to" :
		 "(bogus_direction)", state->remote_endpt);
	state->req_flags = req_flags;
	state->timeout = timeout + 10;		/* XXX */
	event_enable_read(plaintext_fd, tlsp_get_fd_event, (char *) state);
	event_request_timer(tlsp_get_fd_event, (char *) state,
			    TLSP_INIT_TIMEOUT);
	return;
    }
}