예제 #1
0
void stats_connection_connect(struct stats_connection *conn,
			      struct mail_user *user)
{
	struct stats_user *suser = STATS_USER_CONTEXT(user);
	string_t *str = t_str_new(128);

	str_append(str, "CONNECT\t");
	/* required fields */
	str_append(str, guid_128_to_string(suser->session_guid));
	str_append_c(str, '\t');
	str_append_tabescaped(str, user->username);
	str_append_c(str, '\t');
	str_append_tabescaped(str, user->service);
	str_printfa(str, "\t%s", my_pid);

	/* optional fields */
	if (user->local_ip != NULL) {
		str_append(str, "\tlip=");
		str_append(str, net_ip2addr(user->local_ip));
	}
	if (user->remote_ip != NULL) {
		str_append(str, "\trip=");
		str_append(str, net_ip2addr(user->remote_ip));
	}
	str_append_c(str, '\n');
	stats_connection_send(conn, str);
}
예제 #2
0
static void
login_proxy_cmd_list_reply(struct ipc_cmd *cmd, string_t *str,
			   struct login_proxy *proxy)
{
	unsigned int i, alt_count = array_count(&global_alt_usernames);

	str_truncate(str, 0);
	str_append_tabescaped(str, proxy->client->virtual_user);
	str_append_c(str, '\t');
	i = 0;
	if (proxy->client->alt_usernames != NULL) {
		for (; proxy->client->alt_usernames[i] != NULL; i++) {
			str_append_tabescaped(str, proxy->client->alt_usernames[i]);
			str_append_c(str, '\t');
		}
		i_assert(i <= alt_count);
	}
	for (; i < alt_count; i++)
		str_append_c(str, '\t');

	str_printfa(str, "%s\t%s\t%s\t%u", login_binary->protocol,
		    net_ip2addr(&proxy->client->ip),
		    net_ip2addr(&proxy->ip), proxy->port);
	ipc_cmd_send(cmd, str_c(str));
}
예제 #3
0
static int
client_input_status_dsyncs(struct doveadm_connection *client)
{
	string_t *str = t_str_new(256);
	const ARRAY_TYPE(dsync_client) *clients;
	struct dsync_client *const *clientp;
	const char *username;

	clients = replicator_brain_get_dsync_clients(client->brain);
	array_foreach(clients, clientp) {
		username = dsync_client_get_username(*clientp);
		if (username != NULL) {
			str_append_tabescaped(str, username);
			str_append_c(str, '\t');
			switch (dsync_client_get_type(*clientp)) {
			case DSYNC_TYPE_FULL:
				str_append(str, "full");
				break;
			case DSYNC_TYPE_NORMAL:
				str_append(str, "normal");
				break;
			case DSYNC_TYPE_INCREMENTAL:
				str_append(str, "incremental");
				break;
			}
		} else {
			str_append(str, "\t-");
		}
		str_append_c(str, '\t');
		str_append_tabescaped(str, dsync_client_get_state(*clientp));
		str_append_c(str, '\n');
	}
예제 #4
0
static void verify_plain_callback(enum passdb_result result,
				  struct auth_request *request)
{
	struct auth_worker_client *client = request->context;
	string_t *str;

	if (request->failed && result == PASSDB_RESULT_OK)
		result = PASSDB_RESULT_PASSWORD_MISMATCH;

	str = t_str_new(128);
	str_printfa(str, "%u\t", request->id);

	if (result == PASSDB_RESULT_OK)
		str_append(str, "OK");
	else
		str_printfa(str, "FAIL\t%d", result);
	if (result != PASSDB_RESULT_INTERNAL_FAILURE) {
		str_append_c(str, '\t');
		str_append_tabescaped(str, request->user);
		str_append_c(str, '\t');
		if (request->passdb_password != NULL)
			str_append_tabescaped(str, request->passdb_password);
		reply_append_extra_fields(str, request);
	}
	str_append_c(str, '\n');
	auth_worker_send_reply(client, request, str);

	auth_request_unref(&request);
	auth_worker_client_check_throttle(client);
	auth_worker_client_unref(&client);
}
예제 #5
0
void worker_connection_request(struct worker_connection *conn,
			       const struct indexer_request *request,
			       void *context)
{
	i_assert(worker_connection_is_connected(conn));
	i_assert(context != NULL);
	i_assert(request->index || request->optimize);

	if (conn->request_username == NULL)
		conn->request_username = i_strdup(request->username);
	else {
		i_assert(strcmp(conn->request_username,
				request->username) == 0);
	}

	aqueue_append(conn->request_queue, &context);

	T_BEGIN {
		string_t *str = t_str_new(128);

		str_append_tabescaped(str, request->username);
		str_append_c(str, '\t');
		str_append_tabescaped(str, request->mailbox);
		str_append_c(str, '\t');
		if (request->session_id != NULL)
			str_append_tabescaped(str, request->session_id);
		str_printfa(str, "\t%u\t", request->max_recent_msgs);
		if (request->index)
			str_append_c(str, 'i');
		if (request->optimize)
			str_append_c(str, 'o');
		str_append_c(str, '\n');
		o_stream_nsend(conn->output, str_data(str), str_len(str));
	} T_END;
}
예제 #6
0
파일: fts-storage.c 프로젝트: Raffprta/core
static void fts_queue_index(struct mailbox *box)
{
	struct mail_user *user = box->storage->user;
	string_t *str = t_str_new(256);
	const char *path, *value;
	unsigned int max_recent_msgs;
	int fd;

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

	value = mail_user_plugin_getenv(user, "fts_autoindex_max_recent_msgs");
	if (value == NULL || str_to_uint(value, &max_recent_msgs) < 0)
		max_recent_msgs = 0;

	str_append(str, INDEXER_HANDSHAKE);
	str_append(str, "APPEND\t0\t");
	str_append_tabescaped(str, user->username);
	str_append_c(str, '\t');
	str_append_tabescaped(str, box->vname);
	str_printfa(str, "\t%u", max_recent_msgs);
	str_append_c(str, '\t');
	str_append_tabescaped(str, box->storage->user->session_id);
	str_append_c(str, '\n');
	if (write_full(fd, str_data(str), str_len(str)) < 0)
		i_error("write(%s) failed: %m", path);
	i_close_fd(&fd);
}
예제 #7
0
static int client_export_iter_session(struct client *client)
{
	struct client_export_cmd *cmd = client->cmd_export;
	struct mail_session *session = client->mail_session_iter;

	i_assert(cmd->level == MAIL_EXPORT_LEVEL_SESSION);
	mail_session_unref(&client->mail_session_iter);

	if (!cmd->header_sent) {
		o_stream_nsend_str(client->output,
			"session\tuser\tip\tservice\tpid\tconnected"
			"\tlast_update\tnum_cmds"
			MAIL_STATS_HEADER);
		cmd->header_sent = TRUE;
	}

	for (; session != NULL; session = session->stable_next) {
		if (client_is_busy(client))
			break;
		if (!mail_export_filter_match_session(&cmd->filter, session))
			continue;

		str_truncate(cmd->str, 0);
		T_BEGIN {
			str_append(cmd->str, guid_128_to_string(session->guid));
			str_append_c(cmd->str, '\t');
			str_append_tabescaped(cmd->str, session->user->name);
			str_append_c(cmd->str, '\t');
			if (session->ip != NULL) {
				str_append(cmd->str,
					   net_ip2addr(&session->ip->ip));
			}
			str_append_c(cmd->str, '\t');
			str_append_tabescaped(cmd->str, session->service);
		} T_END;
		str_printfa(cmd->str, "\t%ld", (long)session->pid);
		str_printfa(cmd->str, "\t%d", !session->disconnected);
		client_export_timeval(cmd->str, &session->last_update);
		str_printfa(cmd->str, "\t%u", session->num_cmds);
		client_export_mail_stats(cmd->str, &session->stats);
		str_append_c(cmd->str, '\n');
		o_stream_nsend(client->output, str_data(cmd->str),
			       str_len(cmd->str));
	}

	if (session != NULL) {
		client->mail_session_iter = session;
		mail_session_ref(session);
		return 0;
	}
	return 1;
}
static void
auth_request_handler_reply_success_finish(struct auth_request *request)
{
        struct auth_request_handler *handler = request->handler;
	string_t *str = t_str_new(128);

	if (request->last_penalty != 0 && auth_penalty != NULL) {
		/* reset penalty */
		auth_penalty_update(auth_penalty, request, 0);
	}

	/* sanitize these fields, since the login code currently assumes they
	   are exactly in this format. */
	auth_fields_booleanize(request->extra_fields, "nologin");
	auth_fields_booleanize(request->extra_fields, "proxy");

	str_printfa(str, "OK\t%u\tuser="******"nologin") ||
	    auth_fields_exists(request->extra_fields, "proxy")) {
		/* this request doesn't have to wait for master
		   process to pick it up. delete it */
		auth_request_handler_remove(handler, request);
	}
	handler->callback(str_c(str), handler->context);
}
예제 #9
0
static void
lookup_credentials_callback(enum passdb_result result,
			    const unsigned char *credentials, size_t size,
			    struct auth_request *request)
{
	struct auth_worker_client *client = request->context;
	string_t *str;

	if (request->failed && result == PASSDB_RESULT_OK)
		result = PASSDB_RESULT_PASSWORD_MISMATCH;

	str = t_str_new(128);
	str_printfa(str, "%u\t", request->id);

	if (result != PASSDB_RESULT_OK)
		str_printfa(str, "FAIL\t%d", result);
	else {
		str_append(str, "OK\t");
		str_append_tabescaped(str, request->user);
		str_append_c(str, '\t');
		if (request->credentials_scheme[0] != '\0') {
			str_printfa(str, "{%s.b64}", request->credentials_scheme);
			base64_encode(credentials, size, str);
		} else {
			i_assert(size == 0);
		}
		reply_append_extra_fields(str, request);
	}
	str_append_c(str, '\n');
	auth_worker_send_reply(client, request, str);

	auth_request_unref(&request);
	auth_worker_client_check_throttle(client);
	auth_worker_client_unref(&client);
}
예제 #10
0
static void
lookup_user_callback(enum userdb_result result,
		     struct auth_request *auth_request)
{
	struct auth_worker_client *client = auth_request->context;
	string_t *str;

	str = t_str_new(128);
	str_printfa(str, "%u\t", auth_request->id);
	switch (result) {
	case USERDB_RESULT_INTERNAL_FAILURE:
		str_append(str, "FAIL\t");
		break;
	case USERDB_RESULT_USER_UNKNOWN:
		str_append(str, "NOTFOUND\t");
		break;
	case USERDB_RESULT_OK:
		str_append(str, "OK\t");
		str_append_tabescaped(str, auth_request->user);
		str_append_c(str, '\t');
		auth_fields_append(auth_request->userdb_reply, str, 0, 0);
		if (auth_request->userdb_lookup_tempfailed)
			str_append(str, "\ttempfail");
		break;
	}
	str_append_c(str, '\n');

	auth_worker_send_reply(client, auth_request, str);

	auth_request_unref(&auth_request);
	auth_worker_client_check_throttle(client);
	auth_worker_client_unref(&client);
}
예제 #11
0
static int
client_input_status(struct doveadm_connection *client, const char *const *args)
{
	struct replicator_queue_iter *iter;
	struct replicator_user *user;
	const char *mask = args[0];
	string_t *str = t_str_new(128);

	if (mask == NULL)
		return client_input_status_overview(client);

	iter = replicator_queue_iter_init(client->queue);
	while ((user = replicator_queue_iter_next(iter)) != NULL) {
		if (!wildcard_match(user->username, mask))
			continue;

		str_truncate(str, 0);
		str_append_tabescaped(str, user->username);
		str_append_c(str, '\t');
		str_append(str, replicator_priority_to_str(user->priority));
		str_printfa(str, "\t%lld\t%lld\t%d\n",
			    (long long)user->last_fast_sync,
			    (long long)user->last_full_sync,
			    user->last_sync_failed);
		o_stream_send(client->conn.output, str_data(str), str_len(str));
	}
	replicator_queue_iter_deinit(&iter);
	o_stream_send(client->conn.output, "\n", 1);
	return 0;
}
예제 #12
0
static int client_export_iter_command(struct client *client)
{
	struct client_export_cmd *cmd = client->cmd_export;
	struct mail_command *command = client->mail_cmd_iter;

	i_assert(cmd->level == MAIL_EXPORT_LEVEL_COMMAND);
	mail_command_unref(&client->mail_cmd_iter);

	if (!cmd->header_sent) {
		o_stream_nsend_str(client->output,
			"cmd\targs\tsession\tuser\tlast_update"MAIL_STATS_HEADER);
		cmd->header_sent = TRUE;
	}

	for (; command != NULL; command = command->stable_next) {
		if (client_is_busy(client))
			break;
		if (!mail_export_filter_match_session(&cmd->filter,
						      command->session))
			continue;

		str_truncate(cmd->str, 0);
		str_append_tabescaped(cmd->str, command->name);
		str_append_c(cmd->str, '\t');
		str_append_tabescaped(cmd->str, command->args);
		str_append_c(cmd->str, '\t');
		T_BEGIN {
			str_append(cmd->str,
				   guid_128_to_string(command->session->guid));
			str_append_c(cmd->str, '\t');
			str_append_tabescaped(cmd->str,
					      command->session->user->name);
		} T_END;
		client_export_timeval(cmd->str, &command->last_update);
		client_export_mail_stats(cmd->str, &command->stats);
		str_append_c(cmd->str, '\n');
		o_stream_nsend(client->output, str_data(cmd->str),
			       str_len(cmd->str));
	}

	if (command != NULL) {
		client->mail_cmd_iter = command;
		mail_command_ref(command);
		return 0;
	}
	return 1;
}
static void
auth_str_add_keyvalue(string_t *dest, const char *key, const char *value)
{
	str_append_c(dest, '\t');
	str_append(dest, key);
	str_append_c(dest, '=');
	str_append_tabescaped(dest, value);
}
예제 #14
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;
}
예제 #15
0
static int
replication_fifo_notify(struct mail_user *user,
			enum replication_priority priority)
{
	string_t *str;
	ssize_t ret;

	if (fifo_failed)
		return -1;
	if (fifo_fd == -1) {
		fifo_fd = open(fifo_path, O_WRONLY | O_NONBLOCK);
		if (fifo_fd == -1) {
			i_error("open(%s) failed: %m", fifo_path);
			fifo_failed = TRUE;
			return -1;
		}
	}
	/* <username> \t <priority> */
	str = t_str_new(256);
	str_append_tabescaped(str, user->username);
	str_append_c(str, '\t');
	switch (priority) {
	case REPLICATION_PRIORITY_NONE:
	case REPLICATION_PRIORITY_SYNC:
		i_unreached();
	case REPLICATION_PRIORITY_LOW:
		str_append(str, "low");
		break;
	case REPLICATION_PRIORITY_HIGH:
		str_append(str, "high");
		break;
	}
	str_append_c(str, '\n');
	ret = write(fifo_fd, str_data(str), str_len(str));
	i_assert(ret != 0);
	if (ret != (ssize_t)str_len(str)) {
		if (ret > 0)
			i_error("write(%s) wrote partial data", fifo_path);
		else if (errno == EAGAIN) {
			/* busy, try again later */
			return 0;
		} else if (errno != EPIPE) {
			i_error("write(%s) failed: %m", fifo_path);
		} else {
			/* server was probably restarted, don't bother logging
			   this. */
		}
		if (close(fifo_fd) < 0)
			i_error("close(%s) failed: %m", fifo_path);
		fifo_fd = -1;
		return -1;
	}
	return 1;
}
예제 #16
0
void passdb_blocking_verify_plain(struct auth_request *request)
{
	string_t *str;

	str = t_str_new(128);
	str_printfa(str, "PASSV\t%u\t", request->passdb->passdb->id);
	str_append_tabescaped(str, request->mech_password);
	str_append_c(str, '\t');
	auth_request_export(request, str);

	auth_request_ref(request);
	auth_worker_call(request->pool, request->user, str_c(str),
			 verify_plain_callback, request);
}
static void
user_callback(enum userdb_result result,
	      struct auth_request *auth_request)
{
	struct auth_master_connection *conn = auth_request->master;
	string_t *str;
	const char *value;

	if (auth_request->userdb_lookup_tempfailed)
		result = USERDB_RESULT_INTERNAL_FAILURE;

	if (result == USERDB_RESULT_OK) {
		if (user_verify_restricted_uid(auth_request) < 0)
			result = USERDB_RESULT_INTERNAL_FAILURE;
	}

	str = t_str_new(128);
	switch (result) {
	case USERDB_RESULT_INTERNAL_FAILURE:
		str_printfa(str, "FAIL\t%u", auth_request->id);
		if (auth_request->userdb_lookup_tempfailed) {
			value = auth_fields_find(auth_request->userdb_reply,
						 "reason");
			if (value != NULL)
				str_printfa(str, "\treason=%s", value);
		}
		break;
	case USERDB_RESULT_USER_UNKNOWN:
		str_printfa(str, "NOTFOUND\t%u", auth_request->id);
		break;
	case USERDB_RESULT_OK:
		str_printfa(str, "USER\t%u\t", auth_request->id);
		str_append_tabescaped(str, auth_request->user);
		str_append_c(str, '\t');
		auth_fields_append(auth_request->userdb_reply, str,
				   AUTH_FIELD_FLAG_HIDDEN, 0);
		break;
	}

	if (conn->auth->set->debug) {
		i_debug("userdb out: %s",
			auth_master_reply_hide_passwords(conn, str_c(str)));
	}

	str_append_c(str, '\n');
	o_stream_nsend(conn->output, str_data(str), str_len(str));

	auth_request_unref(&auth_request);
	auth_master_connection_unref(&conn);
}
static void auth_request_handler_auth_fail(struct auth_request_handler *handler,
					   struct auth_request *request,
					   const char *reason)
{
	string_t *str = t_str_new(128);

	auth_request_log_info(request, request->mech->mech_name, "%s", reason);

	str_printfa(str, "FAIL\t%u\treason=", request->id);
	str_append_tabescaped(str, reason);

	handler->callback(str_c(str), handler->context);
	auth_request_handler_remove(handler, request);
}
예제 #19
0
void passdb_blocking_lookup_credentials(struct auth_request *request)
{
	string_t *str;

	str = t_str_new(128);
	str_printfa(str, "PASSL\t%u\t", request->passdb->passdb->id);
	str_append_tabescaped(str, request->credentials_scheme);
	str_append_c(str, '\t');
	auth_request_export(request, str);

	auth_request_ref(request);
	auth_worker_call(request->pool, request->user, str_c(str),
			 lookup_credentials_callback, request);
}
예제 #20
0
static void
dsync_replicator_notify(struct dsync_cmd_context *ctx,
			enum dsync_brain_sync_type sync_type,
			const char *state_str)
{
#define REPLICATOR_HANDSHAKE "VERSION\treplicator-doveadm-client\t1\t0\n"
	const char *path;
	string_t *str;
	int fd;

	path = t_strdup_printf("%s/replicator-doveadm",
			       ctx->ctx.cur_mail_user->set->base_dir);
	fd = net_connect_unix(path);
	if (fd == -1) {
		if (errno == ECONNREFUSED || errno == ENOENT) {
			/* replicator not running on this server. ignore. */
			return;
		}
		i_error("net_connect_unix(%s) failed: %m", path);
		return;
	}
	str = t_str_new(128);
	str_append(str, REPLICATOR_HANDSHAKE"NOTIFY\t");
	str_append_tabescaped(str, ctx->ctx.cur_mail_user->username);
	str_append_c(str, '\t');
	if (sync_type == DSYNC_BRAIN_SYNC_TYPE_FULL)
		str_append_c(str, 'f');
	str_append_c(str, '\t');
	str_append_tabescaped(str, state_str);
	str_append_c(str, '\n');
	if (write_full(fd, str_data(str), str_len(str)) < 0)
		i_error("write(%s) failed: %m", path);
	/* we only wanted to notify replicator. we don't care enough about the
	   answer to wait for it. */
	if (close(fd) < 0)
		i_error("close(%s) failed: %m", path);
}
예제 #21
0
const char *str_tabescape(const char *str)
{
	string_t *tmp;
	const char *p;

	for (p = str; *p != '\0'; p++) {
		if (*p <= '\r') {
			tmp = t_str_new(128);
			str_append_n(tmp, str, p-str);
			str_append_tabescaped(tmp, p);
			return str_c(tmp);
		}
	}
	return str;
}
예제 #22
0
void passdb_blocking_set_credentials(struct auth_request *request,
				     const char *new_credentials)
{
	string_t *str;

	str = t_str_new(128);
	str_printfa(str, "SETCRED\t%u\t", request->passdb->passdb->id);
	str_append_tabescaped(str, new_credentials);
	str_append_c(str, '\t');
	auth_request_export(request, str);

	auth_request_ref(request);
	auth_worker_call(request->pool, request->user, str_c(str),
			 set_credentials_callback, request);
}
예제 #23
0
static void pass_callback_finish(struct auth_request *auth_request,
				 enum passdb_result result)
{
	struct auth_master_connection *conn = auth_request->master;
	string_t *str;

	str = t_str_new(128);
	switch (result) {
	case PASSDB_RESULT_OK:
		if (auth_request->failed || !auth_request->passdb_success) {
			str_printfa(str, "FAIL\t%u", auth_request->id);
			break;
		}
		str_printfa(str, "PASS\t%u\tuser="******"NOTFOUND\t%u", auth_request->id);
		break;
	case PASSDB_RESULT_NEXT:
	case PASSDB_RESULT_PASSWORD_MISMATCH:
	case PASSDB_RESULT_INTERNAL_FAILURE:
		str_printfa(str, "FAIL\t%u", auth_request->id);
		break;
	case PASSDB_RESULT_SCHEME_NOT_AVAILABLE:
		str_printfa(str, "FAIL\t%u\treason=Configured passdbs don't support credentials lookups",
			    auth_request->id);
		break;
	}

	if (conn->auth->set->debug)
		i_debug("passdb out: %s", str_c(str));

	str_append_c(str, '\n');
	o_stream_nsend(conn->output, str_data(str), str_len(str));

	auth_request_unref(&auth_request);
	auth_master_connection_unref(&conn);
}
예제 #24
0
static void imap_hibernate_write_cmd(struct client *client, string_t *cmd,
				     const buffer_t *state, int fd_notify)
{
	struct stat peer_st;

	str_append_tabescaped(cmd, client->user->username);
	str_append_c(cmd, '\t');
	str_append_tabescaped(cmd, client->user->set->mail_log_prefix);
	str_printfa(cmd, "\tidle_notify_interval=%u",
		    client->set->imap_idle_notify_interval);
	if (fstat(client->fd_in, &peer_st) == 0) {
		str_printfa(cmd, "\tpeer_dev_major=%lu\tpeer_dev_minor=%lu\tpeer_ino=%llu",
			    (unsigned long)major(peer_st.st_dev),
			    (unsigned long)minor(peer_st.st_dev),
			    (unsigned long long)peer_st.st_ino);
	}

	if (client->session_id != NULL) {
		str_append(cmd, "\tsession=");
		str_append_tabescaped(cmd, client->session_id);
	}
	if (client->user->local_ip != NULL)
		str_printfa(cmd, "\tlip=%s", net_ip2addr(client->user->local_ip));
	if (client->user->remote_ip != NULL)
		str_printfa(cmd, "\trip=%s", net_ip2addr(client->user->remote_ip));
	if (client->userdb_fields != NULL) {
		string_t *userdb_fields = t_str_new(256);
		unsigned int i;

		for (i = 0; client->userdb_fields[i] != NULL; i++) {
			if (i > 0)
				str_append_c(userdb_fields, '\t');
			str_append_tabescaped(userdb_fields, client->userdb_fields[i]);
		}
		str_append(cmd, "\tuserdb_fields=");
		str_append_tabescaped(cmd, str_c(userdb_fields));
	}
	if (client->user->uid != (uid_t)-1)
		str_printfa(cmd, "\tuid=%s", dec2str(client->user->uid));
	if (client->user->gid != (gid_t)-1)
		str_printfa(cmd, "\tgid=%s", dec2str(client->user->gid));
	str_append(cmd, "\tstats=");
	str_append_tabescaped(cmd, client_stats(client));
	if (client->command_queue != NULL &&
	    strcasecmp(client->command_queue->name, "IDLE") == 0)
		str_append(cmd, "\tidle-cmd");
	if (fd_notify != -1)
		str_append(cmd, "\tnotify_fd");
	str_append(cmd, "\tstate=");
	base64_encode(state->data, state->used, cmd);
	str_append_c(cmd, '\n');
}
예제 #25
0
static int client_export_iter_domain(struct client *client)
{
	struct client_export_cmd *cmd = client->cmd_export;
	struct mail_domain *domain = client->mail_domain_iter;

	i_assert(cmd->level == MAIL_EXPORT_LEVEL_DOMAIN);
	mail_domain_unref(&client->mail_domain_iter);

	if (!cmd->header_sent) {
		o_stream_nsend_str(client->output,
			"domain\treset_timestamp\tlast_update"
			"\tnum_logins\tnum_cmds\tnum_connected_sessions"MAIL_STATS_HEADER);
		cmd->header_sent = TRUE;
	}

	for (; domain != NULL; domain = domain->stable_next) {
		if (client_is_busy(client))
			break;
		if (!mail_export_filter_match_domain(&cmd->filter, domain))
			continue;

		str_truncate(cmd->str, 0);
		str_append_tabescaped(cmd->str, domain->name);
		str_printfa(cmd->str, "\t%ld", (long)domain->reset_timestamp);
		client_export_timeval(cmd->str, &domain->last_update);
		str_printfa(cmd->str, "\t%u\t%u\t%u",
			    domain->num_logins, domain->num_cmds,
			    domain->num_connected_sessions);
		client_export_mail_stats(cmd->str, &domain->stats);
		str_append_c(cmd->str, '\n');
		o_stream_nsend(client->output, str_data(cmd->str),
			       str_len(cmd->str));
	}

	if (domain != NULL) {
		client->mail_domain_iter = domain;
		mail_domain_ref(domain);
		return 0;
	}
	return 1;
}
예제 #26
0
static int client_export_iter_user(struct client *client)
{
	struct client_export_cmd *cmd = client->cmd_export;
	struct mail_user *user = client->mail_user_iter;

	i_assert(cmd->level == MAIL_EXPORT_LEVEL_USER);
	mail_user_unref(&client->mail_user_iter);

	if (!cmd->header_sent) {
		o_stream_nsend_str(client->output,
			"user\treset_timestamp\tlast_update"
			"\tnum_logins\tnum_cmds"MAIL_STATS_HEADER);
		cmd->header_sent = TRUE;
	}

	for (; user != NULL; user = user->stable_next) {
		if (client_is_busy(client))
			break;
		if (!mail_export_filter_match_user(&cmd->filter, user))
			continue;

		str_truncate(cmd->str, 0);
		str_append_tabescaped(cmd->str, user->name);
		str_printfa(cmd->str, "\t%ld", (long)user->reset_timestamp);
		client_export_timeval(cmd->str, &user->last_update);
		str_printfa(cmd->str, "\t%u\t%u",
			    user->num_logins, user->num_cmds);
		client_export_mail_stats(cmd->str, &user->stats);
		str_append_c(cmd->str, '\n');
		o_stream_nsend(client->output, str_data(cmd->str),
			       str_len(cmd->str));
	}

	if (user != NULL) {
		client->mail_user_iter = user;
		mail_user_ref(user);
		return 0;
	}
	return 1;
}
예제 #27
0
static void script_execute_finish(void)
{
	const char *keys_str, *username, *const *keys, *value;
	string_t *reply = t_str_new(512);
	ssize_t ret;

	keys_str = getenv(ENV_USERDB_KEYS);
	if (keys_str == NULL)
		i_fatal(ENV_USERDB_KEYS" environment missing");

	username = getenv("USER");
	if (username == NULL)
		i_fatal("USER environment missing");
	str_append(reply, username);

	for (keys = t_strsplit_spaces(keys_str, " "); *keys != NULL; keys++) {
		value = getenv(t_str_ucase(*keys));
		if (value != NULL) {
			str_append_c(reply, '\t');
			str_append_tabescaped(reply,
					    t_strconcat(t_str_lcase(*keys), "=",
							value, NULL));
		}
	}
	str_append_c(reply, '\n');

	/* finish by sending the fd to the mail process */
	ret = fd_send(SCRIPT_COMM_FD, STDOUT_FILENO,
		      str_data(reply), str_len(reply));
	if (ret == (ssize_t)str_len(reply)) {
		/* success */
	} else {
		if (ret < 0)
			i_error("fd_send() failed: %m");
		else
			i_error("fd_send() sent partial output");
		/* exit with 0 even though we failed. non-0 exit just makes
		   master log an unnecessary error. */
	}
}
static void userdb_callback(enum userdb_result result,
			    struct auth_request *request)
{
        struct auth_request_handler *handler = request->handler;
	string_t *str;
	const char *value;

	i_assert(request->state == AUTH_REQUEST_STATE_USERDB);

	auth_request_set_state(request, AUTH_REQUEST_STATE_FINISHED);

	if (request->userdb_lookup_tempfailed)
		result = USERDB_RESULT_INTERNAL_FAILURE;

	str = t_str_new(128);
	switch (result) {
	case USERDB_RESULT_INTERNAL_FAILURE:
		str_printfa(str, "FAIL\t%u", request->id);
		if (request->userdb_lookup_tempfailed) {
			value = auth_fields_find(request->userdb_reply, "reason");
			if (value != NULL)
				auth_str_add_keyvalue(str, "reason", value);
		}
		break;
	case USERDB_RESULT_USER_UNKNOWN:
		str_printfa(str, "NOTFOUND\t%u", request->id);
		break;
	case USERDB_RESULT_OK:
		str_printfa(str, "USER\t%u\t", request->id);
		str_append_tabescaped(str, request->user);
		auth_str_append_userdb_extra_fields(request, str);
		break;
	}
	handler->master_callback(str_c(str), request->master);

	auth_master_connection_unref(&request->master);
	auth_request_unref(&request);
        auth_request_handler_unref(&handler);
}
예제 #29
0
static void
service_dup_fds(struct service *service)
{
	struct service_listener *const *listeners;
	ARRAY_TYPE(dup2) dups;
	string_t *listener_settings;
	int fd = MASTER_LISTEN_FD_FIRST;
	unsigned int i, count, socket_listener_count;

	/* stdin/stdout is already redirected to /dev/null. Other master fds
	   should have been opened with fd_close_on_exec() so we don't have to
	   worry about them.

	   because the destination fd might be another one's source fd we have
	   to be careful not to overwrite anything. dup() the fd when needed */

        socket_listener_count = 0;
	listeners = array_get(&service->listeners, &count);
	t_array_init(&dups, count + 10);

	switch (service->type) {
	case SERVICE_TYPE_LOG:
		i_assert(fd == MASTER_LISTEN_FD_FIRST);
		services_log_dup2(&dups, service->list, fd,
				  &socket_listener_count);
		fd += socket_listener_count;
		break;
	case SERVICE_TYPE_ANVIL:
		dup2_append(&dups, service_anvil_global->log_fdpass_fd[0],
			    MASTER_ANVIL_LOG_FDPASS_FD);
		/* nonblocking anvil fd must be the first one. anvil treats it
		   as the master's fd */
		dup2_append(&dups, service_anvil_global->nonblocking_fd[0], fd++);
		dup2_append(&dups, service_anvil_global->blocking_fd[0], fd++);
		socket_listener_count += 2;
		break;
	default:
		break;
	}

	/* add listeners */
	listener_settings = t_str_new(256);
	for (i = 0; i < count; i++) {
		if (listeners[i]->fd != -1) {
			str_truncate(listener_settings, 0);
			str_append_tabescaped(listener_settings, listeners[i]->name);

			if (listeners[i]->type == SERVICE_LISTENER_INET) {
				if (listeners[i]->set.inetset.set->ssl)
					str_append(listener_settings, "\tssl");
				if (listeners[i]->set.inetset.set->haproxy)
					str_append(listener_settings, "\thaproxy");
			}
			
			dup2_append(&dups, listeners[i]->fd, fd++);

			env_put(t_strdup_printf("SOCKET%d_SETTINGS=%s",
				socket_listener_count, str_c(listener_settings)));
			socket_listener_count++;
		}
	}

	if (service->login_notify_fd != -1) {
		dup2_append(&dups, service->login_notify_fd,
			    MASTER_LOGIN_NOTIFY_FD);
	}
	switch (service->type) {
	case SERVICE_TYPE_LOG:
	case SERVICE_TYPE_ANVIL:
	case SERVICE_TYPE_CONFIG:
		dup2_append(&dups, null_fd, MASTER_ANVIL_FD);
		break;
	case SERVICE_TYPE_UNKNOWN:
	case SERVICE_TYPE_LOGIN:
	case SERVICE_TYPE_STARTUP:
		dup2_append(&dups, service_anvil_global->blocking_fd[1],
			    MASTER_ANVIL_FD);
		break;
	}
	dup2_append(&dups, service->status_fd[1], MASTER_STATUS_FD);
	if (service->type != SERVICE_TYPE_ANVIL) {
		dup2_append(&dups, service->list->master_dead_pipe_fd[1],
			    MASTER_DEAD_FD);
	} else {
		dup2_append(&dups, global_master_dead_pipe_fd[1],
			    MASTER_DEAD_FD);
	}

	if (service->type == SERVICE_TYPE_LOG) {
		/* keep stderr as-is. this is especially important when
		   log_path=/dev/stderr, but might be helpful even in other
		   situations for logging startup errors */
	} else {
		/* set log file to stderr. dup2() here immediately so that
		   we can set up logging to it without causing any log messages
		   to be lost. */
		i_assert(service->log_fd[1] != -1);

		env_put("LOG_SERVICE=1");
		if (dup2(service->log_fd[1], STDERR_FILENO) < 0)
			i_fatal("dup2(log fd) failed: %m");
		i_set_failure_internal();
	}

	/* make sure we don't leak syslog fd. try to do it as late as possible,
	   but also before dup2()s in case syslog fd is one of them. */
	closelog();

	if (dup2_array(&dups) < 0)
		i_fatal("service(%s): dup2s failed", service->set->name);

	i_assert(fd == MASTER_LISTEN_FD_FIRST + (int)socket_listener_count);
	env_put(t_strdup_printf("SOCKET_COUNT=%d", socket_listener_count));
}
예제 #30
0
int subsfile_set_subscribed(struct mailbox_list *list, const char *path,
			    const char *temp_prefix, const char *name,
			    bool set)
{
	const struct mail_storage_settings *mail_set = list->mail_set;
	struct dotlock_settings dotlock_set;
	struct dotlock *dotlock;
	struct mailbox_permissions perm;
	const char *line, *dir, *fname, *escaped_name;
	struct istream *input = NULL;
	struct ostream *output;
	int fd_in, fd_out;
	enum mailbox_list_path_type type;
	bool found, changed = FALSE, failed = FALSE;
	unsigned int version = 2;

	if (strcasecmp(name, "INBOX") == 0)
		name = "INBOX";

	memset(&dotlock_set, 0, sizeof(dotlock_set));
	dotlock_set.use_excl_lock = mail_set->dotlock_use_excl;
	dotlock_set.nfs_flush = mail_set->mail_nfs_storage;
	dotlock_set.temp_prefix = temp_prefix;
	dotlock_set.timeout = SUBSCRIPTION_FILE_LOCK_TIMEOUT;
	dotlock_set.stale_timeout = SUBSCRIPTION_FILE_CHANGE_TIMEOUT;

	mailbox_list_get_root_permissions(list, &perm);
	fd_out = file_dotlock_open_group(&dotlock_set, path, 0,
					 perm.file_create_mode,
					 perm.file_create_gid,
					 perm.file_create_gid_origin, &dotlock);
	if (fd_out == -1 && errno == ENOENT) {
		/* directory hasn't been created yet. */
		type = list->set.control_dir != NULL ?
			MAILBOX_LIST_PATH_TYPE_CONTROL :
			MAILBOX_LIST_PATH_TYPE_DIR;
		fname = strrchr(path, '/');
		if (fname != NULL) {
			dir = t_strdup_until(path, fname);
			if (mailbox_list_mkdir_root(list, dir, type) < 0)
				return -1;
		}
		fd_out = file_dotlock_open_group(&dotlock_set, path, 0,
						 perm.file_create_mode,
						 perm.file_create_gid,
						 perm.file_create_gid_origin,
						 &dotlock);
	}
	if (fd_out == -1) {
		if (errno == EAGAIN) {
			mailbox_list_set_error(list, MAIL_ERROR_TEMP,
				"Timeout waiting for subscription file lock");
		} else {
			subswrite_set_syscall_error(list, "file_dotlock_open()",
						    path);
		}
		return -1;
	}

	fd_in = nfs_safe_open(path, O_RDONLY);
	if (fd_in == -1 && errno != ENOENT) {
		subswrite_set_syscall_error(list, "open()", path);
		file_dotlock_delete(&dotlock);
		return -1;
	}
	if (fd_in != -1) {
		input = i_stream_create_fd_autoclose(&fd_in, list->mailbox_name_max_length+1);
		i_stream_set_return_partial_line(input, TRUE);
		subsfile_list_read_header(list, input, &version);
	}

	found = FALSE;
	output = o_stream_create_fd_file(fd_out, 0, FALSE);
	o_stream_cork(output);
	if (version >= 2)
		o_stream_send_str(output, version2_header);
	if (version < 2 || name[0] == '\0')
		escaped_name = name;
	else {
		const char *const *tmp;
		char separators[2];
		string_t *str = t_str_new(64);

		separators[0] = mailbox_list_get_hierarchy_sep(list);
		separators[1] = '\0';
		tmp = t_strsplit(name, separators);
		str_append_tabescaped(str, *tmp);
		for (tmp++; *tmp != NULL; tmp++) {
			str_append_c(str, '\t');
			str_append_tabescaped(str, *tmp);
		}
		escaped_name = str_c(str);
	}
	if (input != NULL) {
		while ((line = next_line(list, path, input,
					 &failed, FALSE)) != NULL) {
			if (strcmp(line, escaped_name) == 0) {
				found = TRUE;
				if (!set) {
					changed = TRUE;
					continue;
				}
			}

			o_stream_nsend_str(output, line);
			o_stream_nsend(output, "\n", 1);
		}
		i_stream_destroy(&input);
	}

	if (!failed && set && !found) {
		/* append subscription */
		line = t_strconcat(escaped_name, "\n", NULL);
		o_stream_nsend_str(output, line);
		changed = TRUE;
	}

	if (changed && !failed) {
		if (o_stream_nfinish(output) < 0) {
			subswrite_set_syscall_error(list, "write()", path);
			failed = TRUE;
		} else if (mail_set->parsed_fsync_mode != FSYNC_MODE_NEVER) {
			if (fsync(fd_out) < 0) {
				subswrite_set_syscall_error(list, "fsync()",
							    path);
				failed = TRUE;
			}
		}
	} else {
		o_stream_ignore_last_errors(output);
	}
	o_stream_destroy(&output);

	if (failed || !changed) {
		if (file_dotlock_delete(&dotlock) < 0) {
			subswrite_set_syscall_error(list,
				"file_dotlock_delete()", path);
			failed = TRUE;
		}
	} else {
		enum dotlock_replace_flags flags =
			DOTLOCK_REPLACE_FLAG_VERIFY_OWNER;
		if (file_dotlock_replace(&dotlock, flags) < 0) {
			subswrite_set_syscall_error(list,
				"file_dotlock_replace()", path);
			failed = TRUE;
		}
	}
	return failed ? -1 : (changed ? 1 : 0);
}