Beispiel #1
0
static void
exec_child(struct master_service_connection *conn, const char *const *args)
{
	unsigned int i, socket_count;

	if (dup2(conn->fd, STDIN_FILENO) < 0)
		i_fatal("dup2() failed: %m");
	if (dup2(conn->fd, STDOUT_FILENO) < 0)
		i_fatal("dup2() failed: %m");

	/* close all fds */
	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");
	if (close(conn->fd) < 0)
		i_error("close(conn->fd) failed: %m");

	for (; *args != NULL; args++)
		array_append(&exec_args, args, 1);
	array_append_zero(&exec_args);

	env_clean();
	args = array_idx(&exec_args, 0);
	execvp_const(args[0], args);
}
Beispiel #2
0
static void ssl_params_close_listeners(void)
{
	unsigned int i;

	/* we have forked, but the fds are still shared. we can't go
	   io_remove()ing the fds from ioloop, because with many ioloops
	   (e.g. epoll) the fds get removed from the main process's ioloop
	   as well. so we'll just do the closing here manually. */
	for (i = 0; i < master_service_get_socket_count(master_service); i++) {
		int fd = MASTER_LISTEN_FD_FIRST + i;

		if (close(fd) < 0)
			i_error("close(listener %d) failed: %m", fd);
	}
}
Beispiel #3
0
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);
}