コード例 #1
0
static int
master_service_open_config(struct master_service *service,
			   const struct master_service_settings_input *input,
			   const char **path_r, const char **error_r)
{
	struct stat st;
	const char *path;
	int fd;

	*path_r = path = input->config_path != NULL ? input->config_path :
		master_service_get_config_path(service);

	if (service->config_fd != -1 && input->config_path == NULL &&
	    !service->config_path_changed_with_param) {
		/* use the already opened config socket */
		fd = service->config_fd;
		service->config_fd = -1;
		return fd;
	}

	if (!service->config_path_from_master &&
	    !service->config_path_changed_with_param &&
	    input->config_path == NULL) {
		/* first try to connect to the default config socket.
		   configuration may contain secrets, so in default config
		   this fails because the socket is 0600. it's useful for
		   developers though. :) */
		fd = net_connect_unix(DOVECOT_CONFIG_SOCKET_PATH);
		if (fd >= 0) {
			*path_r = DOVECOT_CONFIG_SOCKET_PATH;
			net_set_nonblock(fd, FALSE);
			return fd;
		}
		/* fallback to executing doveconf */
	}

	if (stat(path, &st) < 0) {
		*error_r = errno == EACCES ? eacces_error_get("stat", path) :
			t_strdup_printf("stat(%s) failed: %m", path);
		return -1;
	}

	if (!S_ISSOCK(st.st_mode) && !S_ISFIFO(st.st_mode)) {
		/* it's not an UNIX socket, don't even try to connect */
		fd = -1;
		errno = ENOTSOCK;
	} else {
		fd = net_connect_unix_with_retries(path, 1000);
	}
	if (fd < 0) {
		*error_r = t_strdup_printf("net_connect_unix(%s) failed: %m",
					   path);
		config_exec_fallback(service, input);
		return -1;
	}
	net_set_nonblock(fd, FALSE);
	return fd;
}
コード例 #2
0
static void stats_top(const char *path, const char *sort_type)
{
	struct top_context ctx;

	memset(&ctx, 0, sizeof(ctx));
	ctx.path = path;
	ctx.fd = doveadm_connect(path);
	ctx.prev_pool = pool_alloconly_create("stats top", 1024*16);
	ctx.cur_pool = pool_alloconly_create("stats top", 1024*16);
	i_array_init(&ctx.lines, 128);
	hash_table_create(&ctx.sessions, default_pool, 0, str_hash, strcmp);
	net_set_nonblock(ctx.fd, FALSE);

	ctx.input = i_stream_create_fd(ctx.fd, (size_t)-1, TRUE);

	if (strstr(sort_type, "cpu") != NULL)
		ctx.lines_sort = sort_cpu;
	else
		ctx.lines_sort = sort_num;
	ctx.sort_type = sort_type;

	stats_top_start(&ctx);
	i_stream_destroy(&ctx.input);
	hash_table_destroy(&ctx.sessions);
	array_free(&ctx.lines);
	pool_unref(&ctx.prev_pool);
	pool_unref(&ctx.cur_pool);
	i_close_fd(&ctx.fd);
}
コード例 #3
0
static ssize_t
i_stream_mail_filter_read_once(struct mail_filter_istream *mstream)
{
	struct istream_private *stream = &mstream->istream;
	ssize_t ret;

	if (mstream->ext_out != NULL) {
		/* we haven't sent everything yet */
		(void)o_stream_send_istream(mstream->ext_out, stream->parent);
		if (mstream->ext_out->stream_errno != 0) {
			stream->istream.stream_errno =
				mstream->ext_out->stream_errno;
			return -1;
		}
		if (i_stream_is_eof(stream->parent)) {
			o_stream_destroy(&mstream->ext_out);
			/* if we wanted to be a blocking stream,
			   from now on the rest of the reads are */
			if (stream->istream.blocking)
				net_set_nonblock(mstream->fd, FALSE);
			if (shutdown(mstream->fd, SHUT_WR) < 0)
				i_error("ext-filter: shutdown() failed: %m");
		}
	}

	i_stream_skip(mstream->ext_in, mstream->prev_ret);
	ret = i_stream_read_copy_from(&stream->istream, mstream->ext_in);
	mstream->prev_ret = ret < 0 ? 0 : ret;
	return ret;
}
コード例 #4
0
ファイル: doveadm-director.c プロジェクト: Raffprta/core
static void director_connect(struct director_context *ctx)
{
#define DIRECTOR_HANDSHAKE "VERSION\tdirector-doveadm\t1\t0\n"
	const char *line;
	int fd;

	fd = doveadm_connect(ctx->socket_path);
	net_set_nonblock(fd, FALSE);

	ctx->input = i_stream_create_fd_autoclose(&fd, (size_t)-1);
	director_send(ctx, DIRECTOR_HANDSHAKE);

	alarm(5);
	line = i_stream_read_next_line(ctx->input);
	alarm(0);
	if (line == NULL) {
		if (ctx->input->stream_errno != 0)
			i_fatal("read(%s) failed: %m", ctx->socket_path);
		else if (ctx->input->eof)
			i_fatal("%s disconnected", ctx->socket_path);
		else {
			i_fatal("read(%s) timed out (is director configured?)",
				ctx->socket_path);
		}
	}
	if (!version_string_verify(line, "director-doveadm", 1)) {
		i_fatal_status(EX_PROTOCOL,
			       "%s not a compatible director-doveadm socket",
			       ctx->socket_path);
	}
}
コード例 #5
0
ファイル: doveadm-penalty.c プロジェクト: LTD-Beget/dovecot
static void penalty_lookup(struct penalty_context *ctx)
{
#define ANVIL_HANDSHAKE "VERSION\tanvil\t1\t0\n"
#define ANVIL_CMD ANVIL_HANDSHAKE"PENALTY-DUMP\n"
	struct istream *input;
	const char *line;
	int fd;

	fd = doveadm_connect(ctx->anvil_path);
	net_set_nonblock(fd, FALSE);
	if (write(fd, ANVIL_CMD, strlen(ANVIL_CMD)) < 0)
		i_fatal("write(%s) failed: %m", ctx->anvil_path);

	input = i_stream_create_fd_autoclose(&fd, (size_t)-1);
	while ((line = i_stream_read_next_line(input)) != NULL) {
		if (*line == '\0')
			break;
		T_BEGIN {
			struct penalty_line penalty_line;

			penalty_parse_line(line, &penalty_line);
			penalty_print_line(ctx, &penalty_line);
		} T_END;
	}
	if (input->stream_errno != 0)
		i_fatal("read(%s) failed: %m", ctx->anvil_path);

	i_stream_destroy(&input);
}
コード例 #6
0
int server_connection_create(struct doveadm_server *server,
			     struct server_connection **conn_r)
{
#define DOVEADM_SERVER_HANDSHAKE "VERSION\tdoveadm-server\t1\t0\n"
	struct server_connection *conn;
	pool_t pool;

	pool = pool_alloconly_create("doveadm server connection", 1024*16);
	conn = p_new(pool, struct server_connection, 1);
	conn->pool = pool;
	conn->server = server;
	conn->fd = doveadm_connect_with_default_port(server->name,
						     doveadm_settings->doveadm_port);
	net_set_nonblock(conn->fd, TRUE);
	conn->io = io_add(conn->fd, IO_READ, server_connection_input, conn);
	conn->input = i_stream_create_fd(conn->fd, MAX_INBUF_SIZE, FALSE);
	conn->output = o_stream_create_fd(conn->fd, (size_t)-1, FALSE);

	array_append(&conn->server->connections, &conn, 1);

	if (server_connection_read_settings(conn) < 0 ||
	    server_connection_init_ssl(conn) < 0) {
		server_connection_destroy(&conn);
		return -1;
	}

	o_stream_set_no_error_handling(conn->output, TRUE);
	conn->state = SERVER_REPLY_STATE_DONE;
	o_stream_nsend_str(conn->output, DOVEADM_SERVER_HANDSHAKE);

	*conn_r = conn;
	return 0;
}
コード例 #7
0
ファイル: imap-urlauth-worker.c プロジェクト: bdraco/dovecot
static struct client *
client_create_standalone(const char *access_user,
			 const char *const *access_applications,
			 int fd_in, int fd_out, bool debug)
{
	struct client *client;

	/* always use nonblocking I/O */
	net_set_nonblock(fd_in, TRUE);
	net_set_nonblock(fd_out, TRUE);

	client = i_new(struct client, 1);
	i_array_init(&client->access_apps, 16);
	client->fd_in = fd_in;
	client->fd_out = fd_out;
	client->fd_ctrl = -1;

	if (access_user != NULL && *access_user != '\0')
		client->access_user = i_strdup(access_user);
	else {
		client->access_user = i_strdup("anonymous");
		client->access_anonymous = TRUE;
	}
	if (access_applications != NULL) {
		const char *const *apps = access_applications;
		for (; *apps != NULL; apps++) {
			char *app = i_strdup(*apps);
			array_append(&client->access_apps, &app, 1);
		}
	}
	client->debug = debug;

	client->input = i_stream_create_fd(fd_in, MAX_INBUF_SIZE, FALSE);
	client->output = o_stream_create_fd(fd_out, (size_t)-1, FALSE);
	client->io = io_add(fd_in, IO_READ, client_input, client);
	client->to_idle = timeout_add(CLIENT_IDLE_TIMEOUT_MSECS,
				      client_idle_timeout, client);
	o_stream_set_flush_callback(client->output, client_output, client);

	imap_urlauth_worker_client_count++;
	DLLIST_PREPEND(&imap_urlauth_worker_clients, client);

	i_set_failure_prefix("imap-urlauth[%s](%s): ",
			     my_pid, client->access_user);
	return client;
}
コード例 #8
0
static int replication_notify_sync(struct mail_user *user)
{
	struct replication_user *ruser = REPLICATION_USER_CONTEXT(user);
	string_t *str;
	char buf[1024];
	int fd;
	ssize_t ret;

	fd = net_connect_unix(ruser->socket_path);
	if (fd == -1) {
		i_error("net_connect_unix(%s) failed: %m", ruser->socket_path);
		return -1;
	}
	net_set_nonblock(fd, FALSE);

	/* <username> \t "sync" */
	str = t_str_new(256);
	str_append_tabescaped(str, user->username);
	str_append(str, "\tsync\n");
	alarm(ruser->sync_secs);
	if (write_full(fd, str_data(str), str_len(str)) < 0) {
		i_error("write(%s) failed: %m", ruser->socket_path);
		ret = -1;
	} else {
		/* + | - */
		ret = read(fd, buf, sizeof(buf));
		if (ret < 0) {
			if (errno != EINTR) {
				i_error("read(%s) failed: %m",
					ruser->socket_path);
			} else {
				i_warning("replication(%s): Sync failure: "
					  "Timeout in %u secs",
					  user->username, ruser->sync_secs);
			}
		} else if (ret == 0) {
			i_error("read(%s) failed: EOF", ruser->socket_path);
			ret = -1;
		} else if (buf[0] == '+') {
			/* success */
			ret = 0;
		} else if (buf[0] == '-') {
			/* failure */
			if (buf[ret-1] == '\n') ret--;
			i_warning("replication(%s): Sync failure: %s",
				  user->username, t_strndup(buf+1, ret-1));
			ret = -1;
		} else {
			i_warning("replication(%s): "
				  "Remote sent invalid input: %s",
				  user->username, t_strndup(buf, ret));
		}
	}
	alarm(0);
	if (close(fd) < 0)
		i_error("close(%s) failed: %m", ruser->socket_path);
	return ret;
}
コード例 #9
0
ファイル: ssl-proxy-gnutls.c プロジェクト: aosm/dovecot
int ssl_proxy_new(int fd, struct ip_addr *ip)
{
        struct ssl_proxy *proxy;
	gnutls_session session;
	int sfd[2];

	if (!ssl_initialized) {
		i_error("SSL support not enabled in configuration");
		return -1;
	}

	session = initialize_state();
	gnutls_transport_set_ptr(session, fd);

	if (socketpair(AF_UNIX, SOCK_STREAM, 0, sfd) == -1) {
		i_error("socketpair() failed: %m");
		gnutls_deinit(session);
		return -1;
	}

	net_set_nonblock(sfd[0], TRUE);
	net_set_nonblock(sfd[1], TRUE);
	net_set_nonblock(fd, TRUE);

	proxy = i_new(struct ssl_proxy, 1);
	proxy->refcount = 1;
	proxy->session = session;
	proxy->fd_ssl = fd;
	proxy->fd_plain = sfd[0];
	proxy->ip = *ip;

	hash_table_insert(ssl_proxies, proxy, proxy);

	proxy->refcount++;
	ssl_handshake(proxy);
	if (!ssl_proxy_destroy(proxy)) {
		/* handshake failed. return the disconnected socket anyway
		   so the caller doesn't try to use the old closed fd */
		return sfd[1];
	}

        main_ref();
	return sfd[1];
}
コード例 #10
0
static int ssl_refresh_parameters(struct master_service *service)
{
#define BUF_APPEND_SIZE 1024
	const char *path;
	buffer_t *buf;
	void *data;
	ssize_t ret;
	int fd;

	if (ioloop_time == 0 ||
	    service->ssl_params_last_refresh > ioloop_time - SSL_PARAMS_CHECK_INTERVAL)
		return 0;
	service->ssl_params_last_refresh = ioloop_time;

	path = t_strdup_printf("%s/"SSL_PARAMETERS_PATH, service->set->base_dir);
	fd = net_connect_unix(path);
	if (fd == -1) {
		i_error("connect(%s) failed: %m", path);
		return -1;
	}
	net_set_nonblock(fd, FALSE);

	buf = buffer_create_dynamic(default_pool, BUF_APPEND_SIZE*2);
	for (;;) {
		data = buffer_append_space_unsafe(buf, BUF_APPEND_SIZE);
		ret = read(fd, data, BUF_APPEND_SIZE);
		buffer_set_used_size(buf, buf->used - BUF_APPEND_SIZE +
				     (ret < 0 ? 0 : ret));
		if (ret <= 0)
			break;
	}
	if (ret < 0)
		i_error("read(%s) failed: %m", path);
	else if (ssl_iostream_context_import_params(service->ssl_ctx, buf) < 0) {
		i_error("Corrupted SSL parameters file in state_dir: "
			"ssl-parameters.dat - disabling SSL %u", (int)buf->used);
		ret = -1;
	}
	i_close_fd(&fd);
	buffer_free(&buf);
	return ret < 0 ? -1 : 0;
}
コード例 #11
0
static void stats_dump(const char *path, const char *cmd)
{
	struct istream *input;
	const char *const *args;
	unsigned int i;
	int fd;

	fd = doveadm_connect(path);
	net_set_nonblock(fd, FALSE);

	input = i_stream_create_fd(fd, (size_t)-1, TRUE);
	if (write_full(fd, cmd, strlen(cmd)) < 0)
		i_fatal("write(%s) failed: %m", path);

	/* read header */
	args = read_next_line(input);
	if (args == NULL)
		i_fatal("read(%s) unexpectedly disconnected", path);
	if (*args == NULL)
		i_info("no statistics available");
	else {
		for (; *args != NULL; args++)
			doveadm_print_header_simple(*args);

		/* read lines */
		do {
			T_BEGIN {
				args = read_next_line(input);
				if (args != NULL && args[0] == NULL)
					args = NULL;
				if (args != NULL) {
					for (i = 0; args[i] != NULL; i++)
						doveadm_print(args[i]);
				}
			} T_END;
		} while (args != NULL);
	}
	if (input->stream_errno != 0)
		i_fatal("read(%s) failed: %m", path);
	i_stream_destroy(&input);
}
コード例 #12
0
static int filter_connect(struct mail_filter_istream *mstream,
			  const char *socket_path, const char *args)
{
	const char **argv;
	string_t *str;
	int fd;

	argv = t_strsplit(args, " ");

	if ((fd = net_connect_unix_with_retries(socket_path, 1000)) < 0) {
		if (errno == EACCES) {
			i_error("ext-filter: %s",
				eacces_error_get("net_connect_unix",
						 socket_path));
		} else {
			i_error("ext-filter: net_connect_unix(%s) failed: %m",
				socket_path);
		}
		return -1;
	}
	if (mstream->istream.istream.blocking)
		net_set_nonblock(fd, FALSE);

	mstream->fd = fd;
	mstream->ext_in =
		i_stream_create_fd(fd, mstream->istream.max_buffer_size, FALSE);
	mstream->ext_out = o_stream_create_fd(fd, 0, FALSE);

	str = t_str_new(256);
	str_append(str, "VERSION\tscript\t3\t0\nnoreply\n");
	for (; *argv != NULL; argv++) {
		str_append(str, *argv);
		str_append_c(str, '\n');
	}
	str_append_c(str, '\n');

	o_stream_send(mstream->ext_out, str_data(str), str_len(str));
	return 0;
}
コード例 #13
0
ファイル: imap-urlauth-worker.c プロジェクト: bdraco/dovecot
static struct client *client_create(int fd)
{
	struct client *client;

	/* always use nonblocking I/O */
	net_set_nonblock(fd, TRUE);

	client = i_new(struct client, 1);
	i_array_init(&client->access_apps, 16);
	client->fd_in = -1;
	client->fd_out = -1;
	client->fd_ctrl = fd;
	client->access_anonymous = TRUE; /* default until overridden */

	client->ctrl_io = io_add(fd, IO_READ, client_ctrl_input, client);
	client->to_idle = timeout_add(CLIENT_IDLE_TIMEOUT_MSECS,
				      client_idle_timeout, client);

	imap_urlauth_worker_client_count++;
	DLLIST_PREPEND(&imap_urlauth_worker_clients, client);

	imap_urlauth_worker_refresh_proctitle();
	return client;
}
コード例 #14
0
static int
imap_hibernate_process_send(struct client *client,
			    const buffer_t *state, int fd_notify)
{
	string_t *cmd = t_str_new(512);
	const char *path;
	ssize_t ret = 0;
	int fd;

	i_assert(state->used > 0);

	path = t_strconcat(client->user->set->base_dir,
			   "/"IMAP_HIBERNATE_SOCKET_NAME, NULL);
	fd = net_connect_unix_with_retries(path, 1000);
	if (fd == -1) {
		i_error("net_connect_unix(%s) failed: %m", path);
		return -1;
	}
	net_set_nonblock(fd, FALSE);

	imap_hibernate_write_cmd(client, cmd, state, fd_notify);

	alarm(IMAP_HIBERNATE_SEND_TIMEOUT_SECS);
	if (imap_hibernate_process_send_cmd(fd, path, cmd, client->fd_in) < 0 ||
	    imap_hibernate_process_read(fd, path) < 0)
		ret = -1;
	else if (fd_notify != -1) {
		if ((ret = fd_send(fd, fd_notify, "\n", 1)) < 0)
			i_error("fd_send(%s) failed: %m", path);
		else
			ret = imap_hibernate_process_read(fd, path);
	}
	alarm(0);
	net_disconnect(fd);
	return ret < 0 ? -1 : 0;
}
コード例 #15
0
static int program_client_local_connect
(struct program_client *pclient)
{
	struct program_client_local *slclient = 
		(struct program_client_local *) pclient;
	int fd[2] = { -1, -1 };
	struct program_client_extra_fd *efds = NULL;
	int *parent_extra_fds = NULL, *child_extra_fds = NULL;
	unsigned int xfd_count = 0, i;

	/* create normal I/O fd */
	if ( pclient->input != NULL || pclient->output != NULL ||
		pclient->output_seekable ) {
		if ( socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0 ) {
			i_error("socketpair() failed: %m");
			return -1;
		}
	}

	/* create pipes for additional output through side-channel fds */
	if ( array_is_created(&pclient->extra_fds) ) {
		int extra_fd[2];
		
		efds = array_get_modifiable(&pclient->extra_fds, &xfd_count);
		if (	xfd_count > 0 ) {
			parent_extra_fds = t_malloc(sizeof(int) * xfd_count);
			child_extra_fds = t_malloc(sizeof(int) * xfd_count * 2 + 1);
			for ( i = 0; i < xfd_count; i++ ) {
				if ( pipe(extra_fd) < 0 ) {
					i_error("pipe() failed: %m");
					return -1;
				}
				parent_extra_fds[i] = extra_fd[0];
				child_extra_fds[i*2+0] = extra_fd[1];
				child_extra_fds[i*2+1] = efds[i].child_fd;
			}
			child_extra_fds[xfd_count*2] = -1;
		}
	}

	/* fork child */
	if ( (slclient->pid = fork()) == (pid_t)-1 ) {
		i_error("fork() failed: %m");

		/* clean up */
		if ( fd[0] >= 0 && close(fd[0]) < 0 ) {
			i_error("close(pipe_fd[0]) failed: %m");
		}
		if ( fd[1] >= 0 && close(fd[1]) < 0 ) {
			i_error("close(pipe_fd[1]) failed: %m");
		}
		for ( i = 0; i < xfd_count; i++ ) {
			if ( close(child_extra_fds[i*2]) < 0 ) {
				i_error("close(extra_fd[1]) failed: %m");
			}
			if ( close(parent_extra_fds[i]) < 0 ) {
				i_error("close(extra_fd[0]) failed: %m");
			}
		}
		return -1;
	}

	if ( slclient->pid == 0 ) {
		unsigned int count;
		const char *const *envs = NULL;

		/* child */
		if ( fd[1] >= 0 && close(fd[1]) < 0 ) {
			i_error("close(pipe_fd[1]) failed: %m");
		}
		for ( i = 0; i < xfd_count; i++ ) {
			if ( close(parent_extra_fds[i]) < 0 )
				i_error("close(extra_fd[0]) failed: %m");
		}

		/* drop privileges if we have any */
		if ( getuid() == 0 ) {
			uid_t uid;
			gid_t gid;

			/* switch back to root */
			if (seteuid(0) < 0)
				i_fatal("seteuid(0) failed: %m");

			/* drop gids first */
			gid = getgid();
			if ( gid == 0 || gid != pclient->set.gid ) {
				if ( pclient->set.gid != 0 )
					gid = pclient->set.gid;
				else
					gid = getegid();
			}
	    if ( setgroups(1, &gid) < 0 )
				i_fatal("setgroups(%d) failed: %m", gid);
			if ( gid != 0 && setgid(gid) < 0 )
				i_fatal("setgid(%d) failed: %m", gid);
		
			/* drop uid */
			if ( pclient->set.uid != 0 )
				uid = pclient->set.uid;
			else
				uid = geteuid();
			if ( uid != 0 && setuid(uid) < 0 )
				i_fatal("setuid(%d) failed: %m", uid);
		}

		i_assert(pclient->set.uid == 0 || getuid() != 0);
		i_assert(pclient->set.gid == 0 || getgid() != 0);

		if ( array_is_created(&pclient->envs) )
			envs = array_get(&pclient->envs, &count);

		exec_child(pclient->path, pclient->args, envs,
			( pclient->input != NULL ? fd[0] : -1 ),
			( pclient->output != NULL || pclient->output_seekable ? fd[0] : -1 ),
			child_extra_fds, pclient->set.drop_stderr);
		i_unreached();
	}

	/* parent */
	if ( fd[0] >= 0 && close(fd[0]) < 0 )
		i_error("close(pipe_fd[0]) failed: %m");
	if ( fd[1] >= 0 ) {
		net_set_nonblock(fd[1], TRUE);
		pclient->fd_in =
			( pclient->output != NULL || pclient->output_seekable ? fd[1] : -1 );
		pclient->fd_out = ( pclient->input != NULL ? fd[1] : -1 );
	}
	for ( i = 0; i < xfd_count; i++ ) {
		if ( close(child_extra_fds[i*2]) < 0 )
			i_error("close(extra_fd[1]) failed: %m");
		net_set_nonblock(parent_extra_fds[i], TRUE);
		efds[i].parent_fd = parent_extra_fds[i];
	}

	program_client_init_streams(pclient);
	return program_client_connected(pclient);
}
コード例 #16
0
ファイル: script.c プロジェクト: zatsepin/core
static bool client_exec_script(struct master_service_connection *conn)
{
	ARRAY_TYPE(const_string) envs;
	const char *const *args;
	string_t *input;
	void *buf;
	size_t prev_size, scanpos;
	bool header_complete = FALSE, noreply = FALSE;
	ssize_t ret;
	int status;
	pid_t pid;

	net_set_nonblock(conn->fd, FALSE);
	input = t_buffer_create(IO_BLOCK_SIZE);

	/* Input contains:

	   VERSION .. <lf>
	   [alarm=<secs> <lf>]
	   "noreply" | "-" (or anything really) <lf>

	   arg 1 <lf>
	   arg 2 <lf>
	   ...
	   <lf>
	   DATA

	   This is quite a horrible protocol. If alarm is specified, it MUST be
	   before "noreply". If "noreply" isn't given, something other string
	   (typically "-") must be given which is eaten away.
	*/		
	alarm(SCRIPT_READ_TIMEOUT_SECS);
	scanpos = 1;
	while (!header_complete) {
		const unsigned char *pos, *end;

		prev_size = input->used;
		buf = buffer_append_space_unsafe(input, IO_BLOCK_SIZE);

		/* peek in socket input buffer */
		ret = recv(conn->fd, buf, IO_BLOCK_SIZE, MSG_PEEK);
		if (ret <= 0) {
			buffer_set_used_size(input, prev_size);
			if (strchr(str_c(input), '\n') != NULL)
				script_verify_version(t_strcut(str_c(input), '\n'));

			if (ret < 0)
				i_fatal("recv(MSG_PEEK) failed: %m");

			i_fatal("recv(MSG_PEEK) failed: disconnected");
		}

		/* scan for final \n\n */
		pos = CONST_PTR_OFFSET(input->data, scanpos);
		end = CONST_PTR_OFFSET(input->data, prev_size + ret);
		for (; pos < end; pos++) {
			if (pos[-1] == '\n' && pos[0] == '\n') {
				header_complete = TRUE;
				pos++;
				break;
			}
		}
		scanpos = pos - (const unsigned char *)input->data;

		/* read data for real (up to and including \n\n) */
		ret = recv(conn->fd, buf, scanpos-prev_size, 0);
		if (prev_size+ret != scanpos) {
			if (ret < 0)
				i_fatal("recv() failed: %m");
			if (ret == 0)
				i_fatal("recv() failed: disconnected");
			i_fatal("recv() failed: size of definitive recv() differs from peek");
		}
		buffer_set_used_size(input, scanpos);
	}
	alarm(0);

	/* drop the last two LFs */
	buffer_set_used_size(input, scanpos-2);

	args = t_strsplit(str_c(input), "\n");
	script_verify_version(*args); args++;
	t_array_init(&envs, 16);
	if (*args != NULL) {
		const char *p;

		if (str_begins(*args, "alarm=")) {
			unsigned int seconds;
			if (str_to_uint(*args + 6, &seconds) < 0)
				i_fatal("invalid alarm option");
			alarm(seconds);
			args++;
		}
		while (str_begins(*args, "env_")) {
			const char *envname, *env;

			env = t_str_tabunescape(*args+4);
			p = strchr(env, '=');
			if (p == NULL)
				i_fatal("invalid environment variable");
			envname = t_strdup_until(*args+4, p);

			if (str_array_find(accepted_envs, envname))
				array_append(&envs, &env, 1);
			args++;
		}
		if (strcmp(*args, "noreply") == 0) {
			noreply = TRUE;
		}
		if (**args == '\0')
			i_fatal("empty options");
		args++;
	}
	array_append_zero(&envs);

	if (noreply) {
		/* no need to fork and check exit status */
		exec_child(conn, args, array_idx(&envs, 0));
		i_unreached();
	}

	if ((pid = fork()) == (pid_t)-1) {
		i_error("fork() failed: %m");
		return FALSE;
	}

	if (pid == 0) {
		/* child */
		exec_child(conn, args, array_idx(&envs, 0));
		i_unreached();
	}

	/* parent */

	/* check script exit status */
	if (waitpid(pid, &status, 0) < 0) {
		i_error("waitpid() failed: %m");
		return FALSE;
	} else if (WIFEXITED(status)) {
		ret = WEXITSTATUS(status);
		if (ret != 0) {
			i_error("Script terminated abnormally, exit status %d", (int)ret);
			return FALSE;
		}
	} else if (WIFSIGNALED(status)) {
		i_error("Script terminated abnormally, signal %d", WTERMSIG(status));
		return FALSE;
	} else if (WIFSTOPPED(status)) {
		i_fatal("Script stopped, signal %d", WSTOPSIG(status));
		return FALSE;
	} else {
		i_fatal("Script terminated abnormally, return status %d", status);
		return FALSE;
	}
	return TRUE;
}
コード例 #17
0
ファイル: script-login.c プロジェクト: Raffprta/core
static void client_connected(struct master_service_connection *conn)
{
	enum mail_storage_service_flags flags =
		MAIL_STORAGE_SERVICE_FLAG_NO_PLUGINS;
	string_t *instr, *keys;
	const char **args, *key, *value, *error, *version_line, *data_line;
	struct mail_storage_service_ctx *service_ctx;
	struct mail_storage_service_input input;
	struct mail_storage_service_user *user;
	char buf[1024];
	unsigned int i, socket_count;
	int fd = -1;
	ssize_t ret;

	alarm(SCRIPT_LOGIN_READ_TIMEOUT_SECS);

	net_set_nonblock(conn->fd, FALSE);
	instr = t_str_new(1024);
	ret = fd_read(conn->fd, buf, sizeof(buf), &fd);
	while (ret > 0) {
		str_append_n(instr, buf, ret);
		if (buf[ret-1] == '\n' &&
		    strchr(str_c(instr), '\n')[1] != '\0') {
			str_truncate(instr, str_len(instr)-1);
			break;
		}

		ret = read(conn->fd, buf, sizeof(buf));
	}

	version_line = str_c(instr);
	data_line = strchr(version_line, '\n');
	if (data_line != NULL)
		version_line = t_strdup_until(version_line, data_line++);
	else
		version_line = NULL;

	if (ret > 0 || version_line != NULL) {
		if (version_line == NULL ||
		    !version_string_verify(version_line, "script-login",
				SCRIPT_LOGIN_PROTOCOL_VERSION_MAJOR)) {
			i_fatal("Client not compatible with this binary "
				"(connecting to wrong socket?)");
		}
	}

	if (ret <= 0) {
		if (ret < 0)
			i_fatal("read() failed: %m");
		else
			i_fatal("read() failed: disconnected");
	}
	if (fd == -1)
		i_fatal("client fd not received");

	alarm(0);

	/* put everything to environment */
	env_clean();
	keys = t_str_new(256);
	args = t_strsplit_tab(data_line);

	if (str_array_length(args) < 3)
		i_fatal("Missing input fields");

	i = 0;
	memset(&input, 0, sizeof(input));
	input.module = "mail"; /* need to get mail_uid, mail_gid */
	input.service = "script-login";
	(void)net_addr2ip(args[i++], &input.local_ip);
	(void)net_addr2ip(args[i++], &input.remote_ip);
	input.username = args[i++];
	input.userdb_fields = args + i;

	env_put(t_strconcat("LOCAL_IP=", net_ip2addr(&input.local_ip), NULL));
	env_put(t_strconcat("IP=", net_ip2addr(&input.remote_ip), NULL));
	env_put(t_strconcat("USER="******"%s ", key);
		}
	}
	env_put(t_strconcat(ENV_USERDB_KEYS"=", str_c(keys), NULL));

	master_service_init_log(master_service,
		t_strdup_printf("script-login(%s): ", input.username));

	if (drop_to_userdb_privileges) {
		service_ctx = mail_storage_service_init(master_service, NULL, flags);
		if (mail_storage_service_lookup(service_ctx, &input, &user, &error) <= 0)
			i_fatal("%s", error);
		mail_storage_service_restrict_setenv(service_ctx, user);
		/* we can't exec anything in a chroot */
		env_remove("RESTRICT_CHROOT");
		restrict_access_by_env(getenv("HOME"), TRUE);
	}

	if (dup2(fd, STDIN_FILENO) < 0)
		i_fatal("dup2() failed: %m");
	if (dup2(fd, STDOUT_FILENO) < 0)
		i_fatal("dup2() failed: %m");
	if (close(fd) < 0)
		i_fatal("close() failed: %m");
	if (conn->fd != SCRIPT_COMM_FD) {
		if (dup2(conn->fd, SCRIPT_COMM_FD) < 0)
			i_fatal("dup2() failed: %m");
		if (close(conn->fd) < 0)
			i_fatal("close() failed: %m");
	}

	/* close all listener sockets */
	socket_count = master_service_get_socket_count(master_service);
	for (i = 0; i < socket_count; i++) {
		if (close(MASTER_LISTEN_FD_FIRST + i) < 0)
			i_error("close(listener) failed: %m");
	}
	if (close(MASTER_STATUS_FD) < 0)
		i_error("close(status) failed: %m");

	execvp_const(exec_args[0], exec_args);
}
コード例 #18
0
ファイル: client-connection.c プロジェクト: bdraco/dovecot
static bool client_handle_command(struct client_connection *conn, char **args)
{
	struct mail_storage_service_input input;
	struct doveadm_mail_cmd_context *ctx;
	const char *flags, *cmd_name;
	unsigned int argc;

	memset(&input, 0, sizeof(input));
	input.service = "doveadm";

	for (argc = 0; args[argc] != NULL; argc++)
		args[argc] = str_tabunescape(args[argc]);

	if (argc < 3) {
		i_error("doveadm client: No command given");
		return FALSE;
	}
	flags = args[0];
	input.username = args[1];
	cmd_name = args[2];
	/* leave the command name as args[0] so getopt() works */
	args += 2;
	argc -= 2;

	doveadm_debug = FALSE;
	doveadm_verbose = FALSE;

	for (; *flags != '\0'; flags++) {
		switch (*flags) {
		case 'D':
			doveadm_debug = TRUE;
			doveadm_verbose = TRUE;
			break;
		case 'v':
			doveadm_verbose = TRUE;
			break;
		default:
			i_error("doveadm client: Unknown flag: %c", *flags);
			return FALSE;
		}
	}

	if (!client_is_allowed_command(conn->set, cmd_name)) {
		i_error("doveadm client isn't allowed to use command: %s",
			cmd_name);
		return FALSE;
	}

	/* make sure client_connection_input() isn't called by the ioloop that
	   is going to be run by doveadm_mail_cmd_server_run() */
	io_remove(&conn->io);

	o_stream_cork(conn->output);
	ctx = doveadm_mail_cmd_server_parse(cmd_name, conn->set, &input, argc, args);
	if (ctx == NULL)
		o_stream_nsend(conn->output, "\n-\n", 3);
	else
		doveadm_mail_cmd_server_run(conn, ctx, &input);
	o_stream_uncork(conn->output);

	/* flush the output and disconnect */
	net_set_nonblock(conn->fd, FALSE);
	(void)o_stream_flush(conn->output);
	net_set_nonblock(conn->fd, TRUE);

	conn->io = io_add(conn->fd, IO_READ, client_connection_input, conn);
	return TRUE;
}
コード例 #19
0
ファイル: submission-client.c プロジェクト: bdraco/core
struct client *client_create(int fd_in, int fd_out,
			     const char *session_id, struct mail_user *user,
			     struct mail_storage_service_user *service_user,
			     const struct submission_settings *set,
			     const char *helo,
			     const unsigned char *pdata, unsigned int pdata_len)
{
	const struct mail_storage_settings *mail_set;
	struct smtp_server_settings smtp_set;
	const char *ident;
	struct client *client;

	/* always use nonblocking I/O */
	net_set_nonblock(fd_in, TRUE);
	net_set_nonblock(fd_out, TRUE);

	client = i_new(struct client, 1);
	client->user = user;
	client->service_user = service_user;
	client->set = set;
	client->session_id = i_strdup(session_id);

	i_zero(&smtp_set);
	smtp_set.hostname = set->hostname;
	smtp_set.login_greeting = set->login_greeting;
	smtp_set.max_recipients = set->submission_max_recipients;
	smtp_set.max_client_idle_time_msecs = CLIENT_IDLE_TIMEOUT_MSECS;
	smtp_set.debug = user->mail_debug;

	client->conn = smtp_server_connection_create(smtp_server,
		fd_in, fd_out, user->conn.remote_ip, user->conn.remote_port,
		FALSE, &smtp_set, &smtp_callbacks, client);

	client_proxy_create(client, set);

	smtp_server_connection_login(client->conn,
		client->user->username, helo,
		pdata, pdata_len, user->conn.ssl_secured);
	smtp_server_connection_start_pending(client->conn);

	mail_set = mail_user_set_get_storage_set(user);
	if (*set->imap_urlauth_host != '\0' &&
	    *mail_set->mail_attribute_dict != '\0') {
		/* Enable BURL capability only when urlauth dict is
		   configured correctly */
		client_init_urlauth(client);
	}

	submission_client_count++;
	DLLIST_PREPEND(&submission_clients, client);

	ident = mail_user_get_anvil_userip_ident(client->user);
	if (ident != NULL) {
		master_service_anvil_send(master_service, t_strconcat(
			"CONNECT\t", my_pid, "\tsubmission/",
			ident, "\n", NULL));
		client->anvil_sent = TRUE;
	}

	if (hook_client_created != NULL)
		hook_client_created(&client);

	submission_refresh_proctitle();
	return client;
}
コード例 #20
0
struct client *client_create(int fd_in, int fd_out, const char *session_id,
			     struct mail_user *user,
			     struct mail_storage_service_user *service_user,
			     const struct imap_settings *set)
{
	const struct mail_storage_settings *mail_set;
	struct client *client;
	const char *ident;
	pool_t pool;
	bool explicit_capability = FALSE;

	/* always use nonblocking I/O */
	net_set_nonblock(fd_in, TRUE);
	net_set_nonblock(fd_out, TRUE);

	pool = pool_alloconly_create("imap client", 2048);
	client = p_new(pool, struct client, 1);
	client->pool = pool;
	client->v = imap_client_vfuncs;
	client->set = set;
	client->service_user = service_user;
	client->session_id = p_strdup(pool, session_id);
	client->fd_in = fd_in;
	client->fd_out = fd_out;
	client->input = i_stream_create_fd(fd_in,
					   set->imap_max_line_length, FALSE);
	client->output = o_stream_create_fd(fd_out, (size_t)-1, FALSE);
	o_stream_set_no_error_handling(client->output, TRUE);
	i_stream_set_name(client->input, "<imap client>");
	o_stream_set_name(client->output, "<imap client>");

	o_stream_set_flush_callback(client->output, client_output, client);

	p_array_init(&client->module_contexts, client->pool, 5);
	client->io = io_add_istream(client->input, client_input, client);
        client->last_input = ioloop_time;
	client->to_idle = timeout_add(CLIENT_IDLE_TIMEOUT_MSECS,
				      client_idle_timeout, client);

	client->command_pool =
		pool_alloconly_create(MEMPOOL_GROWING"client command", 1024*2);
	client->user = user;
	client->notify_count_changes = TRUE;
	client->notify_flag_changes = TRUE;

	mail_namespaces_set_storage_callbacks(user->namespaces,
					      &mail_storage_callbacks, client);

	client->capability_string =
		str_new(client->pool, sizeof(CAPABILITY_STRING)+64);

	if (*set->imap_capability == '\0')
		str_append(client->capability_string, CAPABILITY_STRING);
	else if (*set->imap_capability != '+') {
		explicit_capability = TRUE;
		str_append(client->capability_string, set->imap_capability);
	} else {
		str_append(client->capability_string, CAPABILITY_STRING);
		str_append_c(client->capability_string, ' ');
		str_append(client->capability_string, set->imap_capability + 1);
	}
	if (user->fuzzy_search && !explicit_capability) {
		/* Enable FUZZY capability only when it actually has
		   a chance of working */
		str_append(client->capability_string, " SEARCH=FUZZY");
	}

	mail_set = mail_user_set_get_storage_set(user);
	if (mail_set->mailbox_list_index && !explicit_capability) {
		/* NOTIFY is enabled only when mailbox list indexes are
		   enabled, although even that doesn't necessarily guarantee
		   it always */
		str_append(client->capability_string, " NOTIFY");
	}

	if (*set->imap_urlauth_host != '\0' &&
	    *mail_set->mail_attribute_dict != '\0') {
		/* Enable URLAUTH capability only when dict is
		   configured correctly */
		client_init_urlauth(client);
		if (!explicit_capability)
			str_append(client->capability_string, " URLAUTH URLAUTH=BINARY");
	}
	if (set->imap_metadata && *mail_set->mail_attribute_dict != '\0') {
		client->imap_metadata_enabled = TRUE;
		if (!explicit_capability)
			str_append(client->capability_string, " METADATA");
	}
	if (!explicit_capability && user_has_special_use_mailboxes(user)) {
		/* Advertise SPECIAL-USE only if there are actually some
		   SPECIAL-USE flags in mailbox configuration. */
		str_append(client->capability_string, " SPECIAL-USE");
	}

	ident = mail_user_get_anvil_userip_ident(client->user);
	if (ident != NULL) {
		master_service_anvil_send(master_service, t_strconcat(
			"CONNECT\t", my_pid, "\timap/", ident, "\n", NULL));
		client->anvil_sent = TRUE;
	}

	imap_client_count++;
	DLLIST_PREPEND(&imap_clients, client);
	if (hook_client_created != NULL)
		hook_client_created(&client);

	imap_refresh_proctitle();
	return client;
}
コード例 #21
0
int main( int argc, char *argv[] )
{
    int ret = 0, len, server_fd, i, written, frags;
    unsigned char buf[SSL_MAX_CONTENT_LEN + 1];
#if defined(POLARSSL_KEY_EXCHANGE__SOME__PSK_ENABLED)
    unsigned char psk[POLARSSL_PSK_MAX_LEN];
    size_t psk_len = 0;
#endif
#if defined(POLARSSL_SSL_ALPN)
    const char *alpn_list[10];
#endif
    const char *pers = "ssl_client2";

    entropy_context entropy;
    ctr_drbg_context ctr_drbg;
    ssl_context ssl;
    ssl_session saved_session;
#if defined(POLARSSL_X509_CRT_PARSE_C)
    x509_crt cacert;
    x509_crt clicert;
    pk_context pkey;
#endif
    char *p, *q;
    const int *list;

    /*
     * Make sure memory references are valid.
     */
    server_fd = 0;
    memset( &ssl, 0, sizeof( ssl_context ) );
    memset( &saved_session, 0, sizeof( ssl_session ) );
#if defined(POLARSSL_X509_CRT_PARSE_C)
    x509_crt_init( &cacert );
    x509_crt_init( &clicert );
    pk_init( &pkey );
#endif
#if defined(POLARSSL_SSL_ALPN)
    memset( (void * ) alpn_list, 0, sizeof( alpn_list ) );
#endif

    if( argc == 0 )
    {
    usage:
        if( ret == 0 )
            ret = 1;

        printf( USAGE );

        list = ssl_list_ciphersuites();
        while( *list )
        {
            printf(" %-42s", ssl_get_ciphersuite_name( *list ) );
            list++;
            if( !*list )
                break;
            printf(" %s\n", ssl_get_ciphersuite_name( *list ) );
            list++;
        }
        printf("\n");
        goto exit;
    }

    opt.server_name         = DFL_SERVER_NAME;
    opt.server_addr         = DFL_SERVER_ADDR;
    opt.server_port         = DFL_SERVER_PORT;
    opt.debug_level         = DFL_DEBUG_LEVEL;
    opt.nbio                = DFL_NBIO;
    opt.request_page        = DFL_REQUEST_PAGE;
    opt.request_size        = DFL_REQUEST_SIZE;
    opt.ca_file             = DFL_CA_FILE;
    opt.ca_path             = DFL_CA_PATH;
    opt.crt_file            = DFL_CRT_FILE;
    opt.key_file            = DFL_KEY_FILE;
    opt.psk                 = DFL_PSK;
    opt.psk_identity        = DFL_PSK_IDENTITY;
    opt.force_ciphersuite[0]= DFL_FORCE_CIPHER;
    opt.renegotiation       = DFL_RENEGOTIATION;
    opt.allow_legacy        = DFL_ALLOW_LEGACY;
    opt.renegotiate         = DFL_RENEGOTIATE;
    opt.min_version         = DFL_MIN_VERSION;
    opt.max_version         = DFL_MAX_VERSION;
    opt.auth_mode           = DFL_AUTH_MODE;
    opt.mfl_code            = DFL_MFL_CODE;
    opt.trunc_hmac          = DFL_TRUNC_HMAC;
    opt.reconnect           = DFL_RECONNECT;
    opt.reco_delay          = DFL_RECO_DELAY;
    opt.tickets             = DFL_TICKETS;
    opt.alpn_string         = DFL_ALPN_STRING;

    for( i = 1; i < argc; i++ )
    {
        p = argv[i];
        if( ( q = strchr( p, '=' ) ) == NULL )
            goto usage;
        *q++ = '\0';

        if( strcmp( p, "server_name" ) == 0 )
            opt.server_name = q;
        else if( strcmp( p, "server_addr" ) == 0 )
            opt.server_addr = q;
        else if( strcmp( p, "server_port" ) == 0 )
        {
            opt.server_port = atoi( q );
            if( opt.server_port < 1 || opt.server_port > 65535 )
                goto usage;
        }
        else if( strcmp( p, "debug_level" ) == 0 )
        {
            opt.debug_level = atoi( q );
            if( opt.debug_level < 0 || opt.debug_level > 65535 )
                goto usage;
        }
        else if( strcmp( p, "nbio" ) == 0 )
        {
            opt.nbio = atoi( q );
            if( opt.nbio < 0 || opt.nbio > 2 )
                goto usage;
        }
        else if( strcmp( p, "request_page" ) == 0 )
            opt.request_page = q;
        else if( strcmp( p, "request_size" ) == 0 )
        {
            opt.request_size = atoi( q );
            if( opt.request_size < 0 || opt.request_size > SSL_MAX_CONTENT_LEN )
                goto usage;
        }
        else if( strcmp( p, "ca_file" ) == 0 )
            opt.ca_file = q;
        else if( strcmp( p, "ca_path" ) == 0 )
            opt.ca_path = q;
        else if( strcmp( p, "crt_file" ) == 0 )
            opt.crt_file = q;
        else if( strcmp( p, "key_file" ) == 0 )
            opt.key_file = q;
        else if( strcmp( p, "psk" ) == 0 )
            opt.psk = q;
        else if( strcmp( p, "psk_identity" ) == 0 )
            opt.psk_identity = q;
        else if( strcmp( p, "force_ciphersuite" ) == 0 )
        {
            opt.force_ciphersuite[0] = ssl_get_ciphersuite_id( q );

            if( opt.force_ciphersuite[0] == 0 )
            {
                ret = 2;
                goto usage;
            }
            opt.force_ciphersuite[1] = 0;
        }
        else if( strcmp( p, "renegotiation" ) == 0 )
        {
            opt.renegotiation = (atoi( q )) ? SSL_RENEGOTIATION_ENABLED :
                                              SSL_RENEGOTIATION_DISABLED;
        }
        else if( strcmp( p, "allow_legacy" ) == 0 )
        {
            opt.allow_legacy = atoi( q );
            if( opt.allow_legacy < 0 || opt.allow_legacy > 1 )
                goto usage;
        }
        else if( strcmp( p, "renegotiate" ) == 0 )
        {
            opt.renegotiate = atoi( q );
            if( opt.renegotiate < 0 || opt.renegotiate > 1 )
                goto usage;
        }
        else if( strcmp( p, "reconnect" ) == 0 )
        {
            opt.reconnect = atoi( q );
            if( opt.reconnect < 0 || opt.reconnect > 2 )
                goto usage;
        }
        else if( strcmp( p, "reco_delay" ) == 0 )
        {
            opt.reco_delay = atoi( q );
            if( opt.reco_delay < 0 )
                goto usage;
        }
        else if( strcmp( p, "tickets" ) == 0 )
        {
            opt.tickets = atoi( q );
            if( opt.tickets < 0 || opt.tickets > 2 )
                goto usage;
        }
        else if( strcmp( p, "alpn" ) == 0 )
        {
            opt.alpn_string = q;
        }
        else if( strcmp( p, "min_version" ) == 0 )
        {
            if( strcmp( q, "ssl3" ) == 0 )
                opt.min_version = SSL_MINOR_VERSION_0;
            else if( strcmp( q, "tls1" ) == 0 )
                opt.min_version = SSL_MINOR_VERSION_1;
            else if( strcmp( q, "tls1_1" ) == 0 )
                opt.min_version = SSL_MINOR_VERSION_2;
            else if( strcmp( q, "tls1_2" ) == 0 )
                opt.min_version = SSL_MINOR_VERSION_3;
            else
                goto usage;
        }
        else if( strcmp( p, "max_version" ) == 0 )
        {
            if( strcmp( q, "ssl3" ) == 0 )
                opt.max_version = SSL_MINOR_VERSION_0;
            else if( strcmp( q, "tls1" ) == 0 )
                opt.max_version = SSL_MINOR_VERSION_1;
            else if( strcmp( q, "tls1_1" ) == 0 )
                opt.max_version = SSL_MINOR_VERSION_2;
            else if( strcmp( q, "tls1_2" ) == 0 )
                opt.max_version = SSL_MINOR_VERSION_3;
            else
                goto usage;
        }
        else if( strcmp( p, "force_version" ) == 0 )
        {
            if( strcmp( q, "ssl3" ) == 0 )
            {
                opt.min_version = SSL_MINOR_VERSION_0;
                opt.max_version = SSL_MINOR_VERSION_0;
            }
            else if( strcmp( q, "tls1" ) == 0 )
            {
                opt.min_version = SSL_MINOR_VERSION_1;
                opt.max_version = SSL_MINOR_VERSION_1;
            }
            else if( strcmp( q, "tls1_1" ) == 0 )
            {
                opt.min_version = SSL_MINOR_VERSION_2;
                opt.max_version = SSL_MINOR_VERSION_2;
            }
            else if( strcmp( q, "tls1_2" ) == 0 )
            {
                opt.min_version = SSL_MINOR_VERSION_3;
                opt.max_version = SSL_MINOR_VERSION_3;
            }
            else
                goto usage;
        }
        else if( strcmp( p, "auth_mode" ) == 0 )
        {
            if( strcmp( q, "none" ) == 0 )
                opt.auth_mode = SSL_VERIFY_NONE;
            else if( strcmp( q, "optional" ) == 0 )
                opt.auth_mode = SSL_VERIFY_OPTIONAL;
            else if( strcmp( q, "required" ) == 0 )
                opt.auth_mode = SSL_VERIFY_REQUIRED;
            else
                goto usage;
        }
        else if( strcmp( p, "max_frag_len" ) == 0 )
        {
            if( strcmp( q, "512" ) == 0 )
                opt.mfl_code = SSL_MAX_FRAG_LEN_512;
            else if( strcmp( q, "1024" ) == 0 )
                opt.mfl_code = SSL_MAX_FRAG_LEN_1024;
            else if( strcmp( q, "2048" ) == 0 )
                opt.mfl_code = SSL_MAX_FRAG_LEN_2048;
            else if( strcmp( q, "4096" ) == 0 )
                opt.mfl_code = SSL_MAX_FRAG_LEN_4096;
            else
                goto usage;
        }
        else if( strcmp( p, "trunc_hmac" ) == 0 )
        {
            opt.trunc_hmac = atoi( q );
            if( opt.trunc_hmac < 0 || opt.trunc_hmac > 1 )
                goto usage;
        }
        else
            goto usage;
    }

#if defined(POLARSSL_DEBUG_C)
    debug_set_threshold( opt.debug_level );
#endif

    if( opt.force_ciphersuite[0] > 0 )
    {
        const ssl_ciphersuite_t *ciphersuite_info;
        ciphersuite_info = ssl_ciphersuite_from_id( opt.force_ciphersuite[0] );

        if( opt.max_version != -1 &&
            ciphersuite_info->min_minor_ver > opt.max_version )
        {
            printf("forced ciphersuite not allowed with this protocol version\n");
            ret = 2;
            goto usage;
        }
        if( opt.min_version != -1 &&
            ciphersuite_info->max_minor_ver < opt.min_version )
        {
            printf("forced ciphersuite not allowed with this protocol version\n");
            ret = 2;
            goto usage;
        }
        if( opt.max_version > ciphersuite_info->max_minor_ver )
            opt.max_version = ciphersuite_info->max_minor_ver;
        if( opt.min_version < ciphersuite_info->min_minor_ver )
            opt.min_version = ciphersuite_info->min_minor_ver;
    }

#if defined(POLARSSL_KEY_EXCHANGE__SOME__PSK_ENABLED)
    /*
     * Unhexify the pre-shared key if any is given
     */
    if( strlen( opt.psk ) )
    {
        unsigned char c;
        size_t j;

        if( strlen( opt.psk ) % 2 != 0 )
        {
            printf("pre-shared key not valid hex\n");
            goto exit;
        }

        psk_len = strlen( opt.psk ) / 2;

        for( j = 0; j < strlen( opt.psk ); j += 2 )
        {
            c = opt.psk[j];
            if( c >= '0' && c <= '9' )
                c -= '0';
            else if( c >= 'a' && c <= 'f' )
                c -= 'a' - 10;
            else if( c >= 'A' && c <= 'F' )
                c -= 'A' - 10;
            else
            {
                printf("pre-shared key not valid hex\n");
                goto exit;
            }
            psk[ j / 2 ] = c << 4;

            c = opt.psk[j + 1];
            if( c >= '0' && c <= '9' )
                c -= '0';
            else if( c >= 'a' && c <= 'f' )
                c -= 'a' - 10;
            else if( c >= 'A' && c <= 'F' )
                c -= 'A' - 10;
            else
            {
                printf("pre-shared key not valid hex\n");
                goto exit;
            }
            psk[ j / 2 ] |= c;
        }
    }
#endif /* POLARSSL_KEY_EXCHANGE__SOME__PSK_ENABLED */

#if defined(POLARSSL_SSL_ALPN)
    if( opt.alpn_string != NULL )
    {
        p = (char *) opt.alpn_string;
        i = 0;

        /* Leave room for a final NULL in alpn_list */
        while( i < (int) sizeof alpn_list - 1 && *p != '\0' )
        {
            alpn_list[i++] = p;

            /* Terminate the current string and move on to next one */
            while( *p != ',' && *p != '\0' )
                p++;
            if( *p == ',' )
                *p++ = '\0';
        }
    }
#endif /* POLARSSL_SSL_ALPN */

    /*
     * 0. Initialize the RNG and the session data
     */
    printf( "\n  . Seeding the random number generator..." );
    fflush( stdout );

    entropy_init( &entropy );
    if( ( ret = ctr_drbg_init( &ctr_drbg, entropy_func, &entropy,
                               (const unsigned char *) pers,
                               strlen( pers ) ) ) != 0 )
    {
        printf( " failed\n  ! ctr_drbg_init returned -0x%x\n", -ret );
        goto exit;
    }

    printf( " ok\n" );

#if defined(POLARSSL_X509_CRT_PARSE_C)
    /*
     * 1.1. Load the trusted CA
     */
    printf( "  . Loading the CA root certificate ..." );
    fflush( stdout );

#if defined(POLARSSL_FS_IO)
    if( strlen( opt.ca_path ) )
        if( strcmp( opt.ca_path, "none" ) == 0 )
            ret = 0;
        else
            ret = x509_crt_parse_path( &cacert, opt.ca_path );
    else if( strlen( opt.ca_file ) )
        if( strcmp( opt.ca_file, "none" ) == 0 )
            ret = 0;
        else
            ret = x509_crt_parse_file( &cacert, opt.ca_file );
    else
#endif
#if defined(POLARSSL_CERTS_C)
        ret = x509_crt_parse( &cacert, (const unsigned char *) test_ca_list,
                strlen( test_ca_list ) );
#else
    {
        ret = 1;
        printf("POLARSSL_CERTS_C not defined.");
    }
#endif
    if( ret < 0 )
    {
        printf( " failed\n  !  x509_crt_parse returned -0x%x\n\n", -ret );
        goto exit;
    }

    printf( " ok (%d skipped)\n", ret );

    /*
     * 1.2. Load own certificate and private key
     *
     * (can be skipped if client authentication is not required)
     */
    printf( "  . Loading the client cert. and key..." );
    fflush( stdout );

#if defined(POLARSSL_FS_IO)
    if( strlen( opt.crt_file ) )
        if( strcmp( opt.crt_file, "none" ) == 0 )
            ret = 0;
        else
            ret = x509_crt_parse_file( &clicert, opt.crt_file );
    else
#endif
#if defined(POLARSSL_CERTS_C)
        ret = x509_crt_parse( &clicert, (const unsigned char *) test_cli_crt,
                strlen( test_cli_crt ) );
#else
    {
        ret = 1;
        printf("POLARSSL_CERTS_C not defined.");
    }
#endif
    if( ret != 0 )
    {
        printf( " failed\n  !  x509_crt_parse returned -0x%x\n\n", -ret );
        goto exit;
    }

#if defined(POLARSSL_FS_IO)
    if( strlen( opt.key_file ) )
        if( strcmp( opt.key_file, "none" ) == 0 )
            ret = 0;
        else
            ret = pk_parse_keyfile( &pkey, opt.key_file, "" );
    else
#endif
#if defined(POLARSSL_CERTS_C)
        ret = pk_parse_key( &pkey, (const unsigned char *) test_cli_key,
                strlen( test_cli_key ), NULL, 0 );
#else
    {
        ret = 1;
        printf("POLARSSL_CERTS_C not defined.");
    }
#endif
    if( ret != 0 )
    {
        printf( " failed\n  !  pk_parse_key returned -0x%x\n\n", -ret );
        goto exit;
    }

    printf( " ok\n" );
#endif /* POLARSSL_X509_CRT_PARSE_C */

    /*
     * 2. Start the connection
     */
    if( opt.server_addr == NULL)
        opt.server_addr = opt.server_name;

    printf( "  . Connecting to tcp/%s/%-4d...", opt.server_addr,
                                                opt.server_port );
    fflush( stdout );

    if( ( ret = net_connect( &server_fd, opt.server_addr,
                                         opt.server_port ) ) != 0 )
    {
        printf( " failed\n  ! net_connect returned -0x%x\n\n", -ret );
        goto exit;
    }

    if( opt.nbio > 0 )
        ret = net_set_nonblock( server_fd );
    else
        ret = net_set_block( server_fd );
    if( ret != 0 )
    {
        printf( " failed\n  ! net_set_(non)block() returned -0x%x\n\n", -ret );
        goto exit;
    }

    printf( " ok\n" );

    /*
     * 3. Setup stuff
     */
    printf( "  . Setting up the SSL/TLS structure..." );
    fflush( stdout );

    if( ( ret = ssl_init( &ssl ) ) != 0 )
    {
        printf( " failed\n  ! ssl_init returned -0x%x\n\n", -ret );
        goto exit;
    }

    printf( " ok\n" );

#if defined(POLARSSL_X509_CRT_PARSE_C)
    if( opt.debug_level > 0 )
        ssl_set_verify( &ssl, my_verify, NULL );
#endif

    ssl_set_endpoint( &ssl, SSL_IS_CLIENT );
    ssl_set_authmode( &ssl, opt.auth_mode );

#if defined(POLARSSL_SSL_MAX_FRAGMENT_LENGTH)
    if( ( ret = ssl_set_max_frag_len( &ssl, opt.mfl_code ) ) != 0 )
    {
        printf( " failed\n  ! ssl_set_max_frag_len returned %d\n\n", ret );
        goto exit;
    }
#endif

#if defined(POLARSSL_SSL_TRUNCATED_HMAC)
    if( opt.trunc_hmac != 0 )
        if( ( ret = ssl_set_truncated_hmac( &ssl, SSL_TRUNC_HMAC_ENABLED ) ) != 0 )
        {
            printf( " failed\n  ! ssl_set_truncated_hmac returned %d\n\n", ret );
            goto exit;
        }
#endif

#if defined(POLARSSL_SSL_ALPN)
    if( opt.alpn_string != NULL )
        if( ( ret = ssl_set_alpn_protocols( &ssl, alpn_list ) ) != 0 )
        {
            printf( " failed\n  ! ssl_set_alpn_protocols returned %d\n\n", ret );
            goto exit;
        }
#endif

    ssl_set_rng( &ssl, ctr_drbg_random, &ctr_drbg );
    ssl_set_dbg( &ssl, my_debug, stdout );

    if( opt.nbio == 2 )
        ssl_set_bio( &ssl, my_recv, &server_fd, my_send, &server_fd );
    else
        ssl_set_bio( &ssl, net_recv, &server_fd, net_send, &server_fd );

#if defined(POLARSSL_SSL_SESSION_TICKETS)
    if( ( ret = ssl_set_session_tickets( &ssl, opt.tickets ) ) != 0 )
    {
        printf( " failed\n  ! ssl_set_session_tickets returned %d\n\n", ret );
        goto exit;
    }
#endif

    if( opt.force_ciphersuite[0] != DFL_FORCE_CIPHER )
        ssl_set_ciphersuites( &ssl, opt.force_ciphersuite );

    ssl_set_renegotiation( &ssl, opt.renegotiation );
    ssl_legacy_renegotiation( &ssl, opt.allow_legacy );

#if defined(POLARSSL_X509_CRT_PARSE_C)
    if( strcmp( opt.ca_path, "none" ) != 0 &&
        strcmp( opt.ca_file, "none" ) != 0 )
    {
        ssl_set_ca_chain( &ssl, &cacert, NULL, opt.server_name );
    }
    if( strcmp( opt.crt_file, "none" ) != 0 &&
        strcmp( opt.key_file, "none" ) != 0 )
    {
        if( ( ret = ssl_set_own_cert( &ssl, &clicert, &pkey ) ) != 0 )
        {
            printf( " failed\n  ! ssl_set_own_cert returned %d\n\n", ret );
            goto exit;
        }
    }
#endif

#if defined(POLARSSL_KEY_EXCHANGE__SOME__PSK_ENABLED)
    if( ( ret = ssl_set_psk( &ssl, psk, psk_len,
                             (const unsigned char *) opt.psk_identity,
                             strlen( opt.psk_identity ) ) ) != 0 )
    {
        printf( " failed\n  ! ssl_set_psk returned %d\n\n", ret );
        goto exit;
    }
#endif

#if defined(POLARSSL_SSL_SERVER_NAME_INDICATION)
    if( ( ret = ssl_set_hostname( &ssl, opt.server_name ) ) != 0 )
    {
        printf( " failed\n  ! ssl_set_hostname returned %d\n\n", ret );
        goto exit;
    }
#endif

    if( opt.min_version != -1 )
        ssl_set_min_version( &ssl, SSL_MAJOR_VERSION_3, opt.min_version );
    if( opt.max_version != -1 )
        ssl_set_max_version( &ssl, SSL_MAJOR_VERSION_3, opt.max_version );

    /*
     * 4. Handshake
     */
    printf( "  . Performing the SSL/TLS handshake..." );
    fflush( stdout );

    while( ( ret = ssl_handshake( &ssl ) ) != 0 )
    {
        if( ret != POLARSSL_ERR_NET_WANT_READ && ret != POLARSSL_ERR_NET_WANT_WRITE )
        {
            printf( " failed\n  ! ssl_handshake returned -0x%x\n", -ret );
            if( ret == POLARSSL_ERR_X509_CERT_VERIFY_FAILED )
                printf(
                    "    Unable to verify the server's certificate. "
                        "Either it is invalid,\n"
                    "    or you didn't set ca_file or ca_path "
                        "to an appropriate value.\n"
                    "    Alternatively, you may want to use "
                        "auth_mode=optional for testing purposes.\n" );
            printf( "\n" );
            goto exit;
        }
    }

    printf( " ok\n    [ Protocol is %s ]\n    [ Ciphersuite is %s ]\n",
            ssl_get_version( &ssl ), ssl_get_ciphersuite( &ssl ) );

#if defined(POLARSSL_SSL_ALPN)
    if( opt.alpn_string != NULL )
    {
        const char *alp = ssl_get_alpn_protocol( &ssl );
        printf( "    [ Application Layer Protocol is %s ]\n",
                alp ? alp : "(none)" );
    }
#endif

    if( opt.reconnect != 0 )
    {
        printf("  . Saving session for reuse..." );
        fflush( stdout );

        if( ( ret = ssl_get_session( &ssl, &saved_session ) ) != 0 )
        {
            printf( " failed\n  ! ssl_get_session returned -0x%x\n\n", -ret );
            goto exit;
        }

        printf( " ok\n" );
    }

#if defined(POLARSSL_X509_CRT_PARSE_C)
    /*
     * 5. Verify the server certificate
     */
    printf( "  . Verifying peer X.509 certificate..." );

    if( ( ret = ssl_get_verify_result( &ssl ) ) != 0 )
    {
        printf( " failed\n" );

        if( ( ret & BADCERT_EXPIRED ) != 0 )
            printf( "  ! server certificate has expired\n" );

        if( ( ret & BADCERT_REVOKED ) != 0 )
            printf( "  ! server certificate has been revoked\n" );

        if( ( ret & BADCERT_CN_MISMATCH ) != 0 )
            printf( "  ! CN mismatch (expected CN=%s)\n", opt.server_name );

        if( ( ret & BADCERT_NOT_TRUSTED ) != 0 )
            printf( "  ! self-signed or not signed by a trusted CA\n" );

        printf( "\n" );
    }
    else
        printf( " ok\n" );

    if( ssl_get_peer_cert( &ssl ) != NULL )
    {
        printf( "  . Peer certificate information    ...\n" );
        x509_crt_info( (char *) buf, sizeof( buf ) - 1, "      ",
                       ssl_get_peer_cert( &ssl ) );
        printf( "%s\n", buf );
    }
#endif /* POLARSSL_X509_CRT_PARSE_C */

    if( opt.renegotiate )
    {
        /*
         * Perform renegotiation (this must be done when the server is waiting
         * for input from our side).
         */
        printf( "  . Performing renegotiation..." );
        fflush( stdout );
        while( ( ret = ssl_renegotiate( &ssl ) ) != 0 )
        {
            if( ret != POLARSSL_ERR_NET_WANT_READ &&
                ret != POLARSSL_ERR_NET_WANT_WRITE )
            {
                printf( " failed\n  ! ssl_renegotiate returned %d\n\n", ret );
                goto exit;
            }
        }
        printf( " ok\n" );
    }

    /*
     * 6. Write the GET request
     */
send_request:
    printf( "  > Write to server:" );
    fflush( stdout );

    if( strcmp( opt.request_page, "SERVERQUIT" ) == 0 )
        len = sprintf( (char *) buf, "%s", opt.request_page );
    else
    {
        size_t tail_len = strlen( GET_REQUEST_END );

        len = snprintf( (char *) buf, sizeof(buf) - 1, GET_REQUEST,
                        opt.request_page );

        /* Add padding to GET request to reach opt.request_size in length */
        if( opt.request_size != DFL_REQUEST_SIZE &&
            len + tail_len < (size_t) opt.request_size )
        {
            memset( buf + len, 'A', opt.request_size - len - tail_len );
            len += opt.request_size - len - tail_len;
        }

        strncpy( (char *) buf + len, GET_REQUEST_END, sizeof(buf) - len - 1 );
        len += tail_len;
    }

    /* Truncate if request size is smaller than the "natural" size */
    if( opt.request_size != DFL_REQUEST_SIZE &&
        len > opt.request_size )
    {
        len = opt.request_size;

        /* Still end with \r\n unless that's really not possible */
        if( len >= 2 ) buf[len - 2] = '\r';
        if( len >= 1 ) buf[len - 1] = '\n';
    }

    for( written = 0, frags = 0; written < len; written += ret, frags++ )
    {
        while( ( ret = ssl_write( &ssl, buf + written, len - written ) ) <= 0 )
        {
            if( ret != POLARSSL_ERR_NET_WANT_READ && ret != POLARSSL_ERR_NET_WANT_WRITE )
            {
                printf( " failed\n  ! ssl_write returned -0x%x\n\n", -ret );
                goto exit;
            }
        }
    }

    buf[written] = '\0';
    printf( " %d bytes written in %d fragments\n\n%s\n", written, frags, (char *) buf );

    /*
     * 7. Read the HTTP response
     */
    printf( "  < Read from server:" );
    fflush( stdout );

    do
    {
        len = sizeof( buf ) - 1;
        memset( buf, 0, sizeof( buf ) );
        ret = ssl_read( &ssl, buf, len );

        if( ret == POLARSSL_ERR_NET_WANT_READ || ret == POLARSSL_ERR_NET_WANT_WRITE )
            continue;

        if( ret == POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY )
            break;

        if( ret < 0 )
        {
            printf( "failed\n  ! ssl_read returned -0x%x\n\n", -ret );
            break;
        }

        if( ret == 0 )
        {
            printf("\n\nEOF\n\n");
            ssl_close_notify( &ssl );
            break;
        }

        len = ret;
        buf[len] = '\0';
        printf( " %d bytes read\n\n%s", len, (char *) buf );
    }
    while( 1 );

    if( opt.reconnect != 0 )
    {
        --opt.reconnect;

        net_close( server_fd );

#if defined(POLARSSL_TIMING_C)
        if( opt.reco_delay > 0 )
            m_sleep( 1000 * opt.reco_delay );
#endif

        printf( "  . Reconnecting with saved session..." );
        fflush( stdout );

        if( ( ret = ssl_session_reset( &ssl ) ) != 0 )
        {
            printf( " failed\n  ! ssl_session_reset returned -0x%x\n\n", -ret );
            goto exit;
        }

        if( ( ret = ssl_set_session( &ssl, &saved_session ) ) != 0 )
        {
            printf( " failed\n  ! ssl_set_session returned %d\n\n", ret );
            goto exit;
        }

        if( ( ret = net_connect( &server_fd, opt.server_name,
                        opt.server_port ) ) != 0 )
        {
            printf( " failed\n  ! net_connect returned -0x%x\n\n", -ret );
            goto exit;
        }

        while( ( ret = ssl_handshake( &ssl ) ) != 0 )
        {
            if( ret != POLARSSL_ERR_NET_WANT_READ &&
                ret != POLARSSL_ERR_NET_WANT_WRITE )
            {
                printf( " failed\n  ! ssl_handshake returned -0x%x\n\n", -ret );
                goto exit;
            }
        }

        printf( " ok\n" );

        goto send_request;
    }

exit:
    if( ret == POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY )
        ret = 0;

#ifdef POLARSSL_ERROR_C
    if( ret != 0 )
    {
        char error_buf[100];
        polarssl_strerror( ret, error_buf, 100 );
        printf("Last error was: -0x%X - %s\n\n", -ret, error_buf );
    }
#endif

    if( server_fd )
        net_close( server_fd );
#if defined(POLARSSL_X509_CRT_PARSE_C)
    x509_crt_free( &clicert );
    x509_crt_free( &cacert );
    pk_free( &pkey );
#endif
    ssl_session_free( &saved_session );
    ssl_free( &ssl );
    ctr_drbg_free( &ctr_drbg );
    entropy_free( &entropy );

    memset( &ssl, 0, sizeof( ssl ) );

#if defined(_WIN32)
    printf( "  + Press Enter to exit this program.\n" );
    fflush( stdout ); getchar();
#endif

    // Shell can not handle large exit numbers -> 1 for errors
    if( ret < 0 )
        ret = 1;

    return( ret );
}
コード例 #22
0
ファイル: client-connection.c プロジェクト: bsmr-dovecot/core
static bool client_handle_command(struct client_connection *conn, char **args)
{
	struct mail_storage_service_input input;
	const char *flags, *cmd_name;
	unsigned int argc;

	memset(&input, 0, sizeof(input));
	input.service = "doveadm";
	input.local_ip = conn->local_ip;
	input.remote_ip = conn->remote_ip;
	input.local_port = conn->local_port;
	input.remote_port = conn->remote_port;

	for (argc = 0; args[argc] != NULL; argc++)
		args[argc] = str_tabunescape(args[argc]);

	if (argc < 3) {
		i_error("doveadm client: No command given");
		return FALSE;
	}
	flags = args[0];
	input.username = args[1];
	cmd_name = args[2];
	/* leave the command name as args[0] so getopt() works */
	args += 2;
	argc -= 2;

	doveadm_debug = FALSE;
	doveadm_verbose = FALSE;

	for (; *flags != '\0'; flags++) {
		switch (*flags) {
		case 'D':
			doveadm_debug = TRUE;
			doveadm_verbose = TRUE;
			break;
		case 'v':
			doveadm_verbose = TRUE;
			break;
		default:
			i_error("doveadm client: Unknown flag: %c", *flags);
			return FALSE;
		}
	}

	if (!client_is_allowed_command(conn->set, cmd_name)) {
		i_error("doveadm client isn't allowed to use command: %s",
			cmd_name);
		return FALSE;
	}

	o_stream_cork(conn->output);
	if (doveadm_cmd_handle(conn, cmd_name, &input, argc, args) < 0)
		o_stream_nsend(conn->output, "\n-\n", 3);
	o_stream_uncork(conn->output);

	/* flush the output and disconnect */
	net_set_nonblock(conn->fd, FALSE);
	(void)o_stream_flush(conn->output);
	net_set_nonblock(conn->fd, TRUE);
	return TRUE;
}
コード例 #23
0
ファイル: main.c プロジェクト: MaG21/linux-http-proxy
int
main(int argc, char **argv)
{
	int                  i;
	int                  n;
	int                  ret;
	int                  sock;
	int                  epollfd;
	struct net_proxy     *proxy;
	struct net_proxy     *newproxy;
	struct epoll_event   *events;
	struct utils_options *opts;

	opts = utils_getopt(argc, argv);

	printf("Init server on port %s ...", opts->port);
	fflush(stdout);

	sock = net_listen(opts->port);
	utils_free_options(opts);
	net_set_nonblock(sock);

	epollfd = epoll_create1(0);
	if(epollfd<0) {
		perror("epoll");
		exit(EXIT_FAILURE);
	}

	proxy = malloc(sizeof(*proxy));
	proxy->fd = sock;
	net_epoll_interface_add(epollfd, proxy);

	puts("Ok");

	events = calloc(MAX_EVENTS, sizeof(*events));

	for( ; ; ) {
		ret = epoll_wait(epollfd, events, MAX_EVENTS, -1);
		if(ret<0) {
			perror("epoll");
			exit(EXIT_FAILURE);
		}

		net_check_sockets(events, ret);

		for(i=0, n=ret; i < n; i++) {
			if(!events[i].data.ptr)
				continue;

			proxy = events[i].data.ptr;

			if(proxy->fd==sock) {
				net_accept_connections(epollfd, sock);
				continue;
			}

			/* proxy */
			if(proxy->remaining) {
				if(proxy->peer.remaining)
					net_close_proxy(proxy);

				ret = net_exchange(proxy->fd, proxy->peer.fd, proxy->remaining);

				if(ret<=0)
					net_close_proxy(proxy);
				continue;
			}

			ret = http_proxy_make_request(epollfd, proxy);
			switch(ret) {
			case -1:
				perror("http_proxy_make_request");
			case 1:
				net_close_proxy(proxy);
				continue;
			}

			/* The server must be watched in another epoll instance */
			newproxy = calloc(1, sizeof(*proxy));

			newproxy->fd             = proxy->peer.fd;
			newproxy->remaining      = proxy->peer.remaining;
			newproxy->peer.fd        = proxy->fd;
			newproxy->peer.remaining = proxy->remaining;
			net_epoll_interface_add(epollfd, proxy);
		}
	}
   return EXIT_SUCCESS;
}